What I do to never have to worry about memory leaks!

SdĂ­let
VloĆŸit
  • čas pƙidĂĄn 30. 06. 2024
  • In this video, I will show you how I deal with memory allocation in C++ so I never have leaks, and I don't even stress about it!
    #cpp #gamedevelopment #programming
    Full guide about pointers 👉đŸ’Ș:
    ‱ You will never ask aga...
    Join my Discord đŸ€–:
    / discord
    Try My Game Midnight Arrow đŸ€©:
    store.steampowered.com/app/23...
    Join this channel if you want to support me đŸ˜»:
    / @lowlevelgamedev9330
    Music: Evan King - Everything is Okay
    Music: Evan King - Spicy Boom
    Music: Evan King - Pocket Universe
    / contextsensitive
    contextsensitive.bandcamp.com/

Komentáƙe • 196

  • @lolcat69
    @lolcat69 Pƙed 23 dny +26

    in my C json parser I allocate memory only once, and it is while reading the files content, so then everything else that might need to access it's contents, like, we have a variable `"kind": "Person"`, instead of doing a copy of that memory, I just do a string view. so basically I just store the pointer to the start of the section I need from the string, and the length of it. I didn't did this in my first prototype, and for tokens I allocated 1024 bytes for each lexeme, but I figured out - mhh, maybe having a fixed limit on that is kinda stupid, and allocating 1024 extra bytes for each token is a bit of an over kill - so by doing a string view, I allocate 1 pointer + 1 size_t, so we just allocate 12 bytes in total :D ( this depends on the size of size_t in your computer and the size of a pointer, but it is still way better than allocating 1024 bytes ) so remember guys, never allocate memory if you don't need to, neither in the stack or the heap, just allocate as much memory as strictly needed for your program to work!

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 23 dny +3

      epic chad project đŸ’ȘđŸ’Ș thanks for sharing it with us

    • @W0lfCL
      @W0lfCL Pƙed 23 dny +3

      As a C newcomer, thx for that gigachad advice

    • @maksymiliank5135
      @maksymiliank5135 Pƙed 23 dny +2

      You should probably still push the string_views to a tree-like structure for fast lookups

    • @lolcat69
      @lolcat69 Pƙed 22 dny

      @@maksymiliank5135 the whole json document is stored in a tree, the string_views are just used for identifiers and stuff like that

    • @ethernet764
      @ethernet764 Pƙed 3 dny

      Currently learning about this technique in Crafting Interpreters

  • @toksic424
    @toksic424 Pƙed 25 dny +75

    1:30 the virgin "Player *p = new Player();" vs the chad "Player p;"

    • @ltecheroffical
      @ltecheroffical Pƙed 25 dny

      I am a virgin and I use "Player p;"

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny +8

      for real đŸ’ȘđŸ’ȘđŸ’ȘđŸ’Ș

    • @niggacockball7995
      @niggacockball7995 Pƙed 24 dny

      cant leak anything if everything is stored on the stack with a 1000 element array!

    • @atackhelikopter4303
      @atackhelikopter4303 Pƙed 24 dny +4

      if you really need a lot of objects of a type and have to use the heap, i would just consider making a whole class to handle the memory alocation and deletion there and it would act just like the regular object, it's easier imo
      edit: here's how the class would look like:
      template
      class HeapObject
      {
      protected:
      T *ob;
      public:
      HeapObject()
      {ob = new T;}
      ~HeapObject()
      {delete ob;}
      void operator=(T a)
      {*ob = a;}
      /// other methods, i can't be bothered to give more examples, it's just here to show that you can do it
      T operator*()
      {return *ob;}
      };

    • @joshuaubani-wokoma4956
      @joshuaubani-wokoma4956 Pƙed 24 dny

      @@atackhelikopter4303can even be an abstract class and the concrete ones will decide the implementations

  • @darkfllame
    @darkfllame Pƙed 25 dny +73

    that's the neat part: you don't

  • @Lelende
    @Lelende Pƙed 25 dny +20

    To be honest, avoiding the heap for any programming at all is a great rule of thumb.
    The edge cases where you'd actually need the heap are pretty few and far in between.

  • @sledgex9
    @sledgex9 Pƙed 25 dny +31

    2:40 let me introduce you to std::make_unique() and std::make_shared(). Almost never use the `new` operator to initialize a smart pointer.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny +3

      well I don't actually use shared pointers like ever :))

    • @Quentillionaire
      @Quentillionaire Pƙed 25 dny

      @@lowlevelgamedev9330 shared pointers cause more problems than they solve in MOST cases so that's good. Unique pointers, however, are an improvement on using the new keyword in every single way so definitely use make_unique instead of using the new keyword if you end up needing to manage your own memory allocation, like when storing large objects on the heap.

    • @kramer3d
      @kramer3d Pƙed 25 dny

      @@lowlevelgamedev9330you dont have to 
 its still recommended to avoid new

    • @tiranito2834
      @tiranito2834 Pƙed 25 dny +8

      And does that help you with memory fragmentation in any way? no? then what do you earn from this? the point of this video is for using stack allocated variables or preallocated static buffers for data. The more static allocations you do, the less you will need to dynamically allocate stuff, the less of a performance hit for your program (less fragmentation and less time wasted waiting for the OS to reserve a chunk of memory for you...). If you need to dynamically allocate, then do so in buffers or large chunks so that you don't have to allocate every single instance one by one individually. It's that simple. Using make_shared and make_unique does not save you from those problems. First, you should try to understand what the heap even is and how it works...

    • @sledgex9
      @sledgex9 Pƙed 25 dny +9

      @@tiranito2834 You grossly misunderstood my comment.

  • @Deadllyus
    @Deadllyus Pƙed 25 dny +18

    Since you are using containers to store your entities, your entities are on the heap (cuz the elements of a container are allocated on the heap), so you are not using stack memory at all. Besides this, nice advice!

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny +4

      yes I know, but that is not my concern, my concern is to not have memory problems. đŸ’Ș

    • @Spartan322
      @Spartan322 Pƙed 25 dny +4

      Contiguous heap memory, stack memory isn't a big deal when you need dynamic size tbf if you get cache locality out of it.

    • @maksymiliank5135
      @maksymiliank5135 Pƙed 23 dny +2

      The only overhead from a heap is the allocation itself. If you allocate the objects as an array you still get all the benefits of cache locality and fast memory access of the stack. And if the size never changes then you don't need to reallocate so using this memory is essentially free.

    • @ezekieloruven
      @ezekieloruven Pƙed 4 dny

      ​@@lowlevelgamedev9330 but using std::vector literally comes with all of the caveats that using new and std::unique_ptr do, just wrapped up in a more convenient container. For example, you need to be ready for std::bad_alloc if you're considering that the other allocations can fail.
      Generally, I really agree with your overall message. Stack allocation is always better than heap allocation, unless you actually need to heap allocate. Using std::vector and friends is an awesome way to manage dynamically allocated memory, too. However, consider using smart pointers instead of the five raw pointers you have (unless they aren't pointers to data that is owned by the object). There's essentially no weight at all for a std::unique_ptr and they are pretty easy to use, not to mention guaranteeing freeing allocated memory in the face of code refactoring and exceptions.
      It is also good to add new tools to your toolkit!

  • @rayboblio
    @rayboblio Pƙed 25 dny

    Just the thing I needed in my current development phase. Thanks for all the great tips, I'm really enjoying your videos.

  • @sledgex9
    @sledgex9 Pƙed 25 dny +9

    4:21 you can probably get rid of the call to `new` in you filedata var. Make use of the appropriate overloaded constructor to create an std::vector initialized with X elements of unsigned char zero initialized aka std::vector fileData(fileSize). And the use it like this "file.read(fileData.data(), fileData.size());". This takes advantage of the fact that a vector is guaranteed to use contiguous memory to store its elements.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny +5

      yeah I actually write my code like this now usually đŸ’Ș, it just wasn't worth the effort changing that code there

  • @legendcat8913
    @legendcat8913 Pƙed 14 dny

    your channel has been invaluable to my coding hobbies, thank you!

  • @sledgex9
    @sledgex9 Pƙed 25 dny +16

    2:21 don't use raw arrays. Use std::array instead. They encode the size in them. Also the compiler would be able to make it as if you used a raw array. Aka zero overhead.

    • @Spartan322
      @Spartan322 Pƙed 25 dny +5

      Technically C arrays have the size encoded too, problem is they love to decay into generic pointers which can absolutely stab you in the back.

  • @AE4i1
    @AE4i1 Pƙed 25 dny +15

    std::pmr::vector my beloved

    • @zanagi
      @zanagi Pƙed 23 dny +1

      Is this the same like vector of pointers?

    • @AE4i1
      @AE4i1 Pƙed 23 dny +1

      @@zanagi No, it's normal vector, but with different allocator (std::vector takes an allocator as second template argument). It basically allows you to preallocate memory block on stack and then suballocate from it. Allocations are fast and close in memory.

  • @furuthebat
    @furuthebat Pƙed 25 dny +17

    Almost every component of my ECS is living on the stack 😅 .. who needs names or endless strings, user input is limited, e.g. player name is max. 24 characters.
    Expect for textures, sound and other assets ... .. there are living in the resource loader, loaded once, freed at the end.
    The only things that are RAII, are my Scenes/Levels, with init(), enter(), exit() ... Methods ... The Scene itself lives in a "Context" variable (held in the Scene manager). When switching scenes, the scene either gets "disabled" or uninit/init.
    Everything else lives in the ECS registry/world, the scenes queries the components there need.

    • @GBSCronoo
      @GBSCronoo Pƙed 25 dny

      So the resource loader would be on the heap? < kind of new to c++

    • @Spartan322
      @Spartan322 Pƙed 25 dny +2

      RAII is the stack though, like anything you create on the stack is managed through RAII, unless its a primitive data type, it will call the constructor on initialization and destructor on leaving the scope, that is RAII.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny +4

      yo this sounds dope, I approve đŸ’ȘđŸ’Ș

    • @maksymiliank5135
      @maksymiliank5135 Pƙed 23 dny

      @@Spartan322 I assume these are defined in some top level function (maybe even in main) and passed around to other functions as pointers/references so RAII will not trigger as often

    • @Spartan322
      @Spartan322 Pƙed 23 dny

      @@maksymiliank5135 Doesn't matter, RAII is stack allocation and that's still the stack, the object itself may allocate on the heap, like smart pointers or vector, but all memory behavior of the object itself is on the stack and anything that doesn't allocate on the heap is stack allocated and also performs RAII.

  • @erc0re526
    @erc0re526 Pƙed 25 dny +1

    Love your content. Are you planning to make a video on your coding style/structure ?

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny +4

      yo that is a good idea, yes đŸ’Ș

    • @erc0re526
      @erc0re526 Pƙed 25 dny

      @@lowlevelgamedev9330 nice!! I noticed your conventions seem clear, no bullshit, efficient !

  • @yaazarai
    @yaazarai Pƙed 24 dny +1

    I wrote a renderer with C++/Vulkan for 2D cad stuff and even in 2-3k lines of code I use new all of 3 times to allocate some command pool objects. Don't need new that often.

  • @sealsharp
    @sealsharp Pƙed 8 dny

    I once worked for a 2d pixel retro-rpg where i did the C++ part and since we are not in the 90ies any more and devices have more than 2 megabytes of RAM we could ignore a lot of the memory management by loading a lot of stuff at the start.

  • @zanagi
    @zanagi Pƙed 23 dny

    Was thinking about this, but my school's game engine uses shared_ptr GameObject and components as a base. Im not sure how i can code without any ptr.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 23 dny +3

      well you know all the schools do that but you don't have to do the same in your code đŸ’ȘđŸ’Ș their example is just a simple didactic thing, I don't even use ecs in my games lol

  • @jupiterbjy
    @jupiterbjy Pƙed 23 dny +1

    Totally agre on 1:30. Some seems to use alloc & pointers way too much even when not needed - just KISS! (Keep It Simple, Stupid)

  • @MisterFanwank
    @MisterFanwank Pƙed 13 dny

    Allocating on the heap is fine. What matters is whether you can predict how much memory you'll need. If you can't, then you won't be able to manage your memory because you don't have a good concept of what it's doing. If you can, then it's simple to just free it all at once way later when you're done with it. As long as you're not interleaving tons of mallocs and frees you won't get into trouble, and that's to say nothing of what's possible when you realize malloc is garbage and you can easily do syscalls yourself. This is the true meaning "of don't allocate more than you need to", advice that's been misconstrued greatly over the years.

  • @lememz
    @lememz Pƙed 6 dny +1

    there's also alloca if you wanna allocate something of unknown size on the stack, yet another L for the heap

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 6 dny

      yeah but you shouldn't really use that as far as I know, it can have very wierd problems

    • @lememz
      @lememz Pƙed 6 dny

      @@lowlevelgamedev9330 it's only really problematic if you still treat it as a heap allocation since it's always going to get popped at the end of the scope, so just don't do dumb stuff like returning the pointer or passing it around to other threads and it's pretty much fine to use, it's perfect for small stuff like the opengl shader compilation message

  • @vladsiaev12
    @vladsiaev12 Pƙed 3 dny

    what if you have a function that returns int how do you check for error code?

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 3 dny

      well I would return an error code as an enum, or, if I need a return, I could take an extra parameter, as a refference, to write the error into that.

  • @trenwar
    @trenwar Pƙed 25 dny +4

    So basically code C++ like how you code in C, only use C++ features if necessary, and avoid unnecessary use of heap

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny +3

      yes you got it đŸ’ȘđŸ’Ș advanced cpp is usefull for things like std::vector but its just too complicated to write that every day

  • @electron2219
    @electron2219 Pƙed 24 dny +1

    If you don't handle threads at the end of program then it will crash and take even longer to close.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 24 dny +2

      that is another story, and they crash because that is a mechanism made by the cpp standard library, to help you not forget to either detatch them or join them. If you make them using windows api I don't think it will crash

  • @lehisluguer9300
    @lehisluguer9300 Pƙed 25 dny +1

    also Destroyers are usefull to make sure delete stuff as soon the Class is destroyed..

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny +2

      well I don't use destroyers in my coding style, except you know vectors and stuff have them, maybe I will make a video on it

    • @lehisluguer9300
      @lehisluguer9300 Pƙed 25 dny

      @@lowlevelgamedev9330 oh ok.. that's fair.. yeah, vectors does the job automatically so.. its ok..

  • @nazihboudaakkar8117
    @nazihboudaakkar8117 Pƙed 25 dny

    Okay, you touched on a subject I've been wanting to know about for long lol
    I have a question tho, I remember once having a vector of entities, the vector was getting passed around quite a lot, you see I have this preference of passing things as parameters instead of making them accessible globally or make a system for them (Unless the need arises)
    However, I had a big problem where the entities vector was getting corrupted somehow? I don't really understand the problem myself but I remember it had an addressing issue, it got fixed when I allocated the entities on the heap
    So my question: if this is wrong, how wrong is it? and how can I potentially fix it?

    • @sledgex9
      @sledgex9 Pƙed 25 dny +2

      You either used the vector wrong or one of the functions you passed it in mutate it accidentally. Either pass it as a const reference (no mutation possible) or as a reference (mutation possible).

    • @nazihboudaakkar8117
      @nazihboudaakkar8117 Pƙed 25 dny

      @@sledgex9 I am sure I was not mutating, the vectors got passed as a "const &" since it was large
      The issue is that i noticed is that the entities within had different addresses for some reason, which was very strange to me

    • @sledgex9
      @sledgex9 Pƙed 25 dny +2

      @@nazihboudaakkar8117 Unfortunately this kind of problem can't be diagnosed via a comment. All I can say is that vectors should work with no problems. Potentially a misuse was happening somewhere. C++ has many pitfalls you can fall into if you aren't experienced, unfortunately.

    • @swansonair
      @swansonair Pƙed 25 dny +2

      If you take a pointer to an item in a vector and then you add/remove things from the vector, it will invalidate the pointer because under the hood reallocation happened.

    • @nazihboudaakkar8117
      @nazihboudaakkar8117 Pƙed 25 dny

      @@swansonair As I said earlier, I was passing the vector around as a const reference precisely to avoid that and to avoid needlessly copying the contents
      The issue got solved the moment i changed the entities to be on the heap, I clearly remember not touching anything (besides refactoring things to use the unique_ptr) and It felt sooo awkward
      But yeah, it was probably a bug on my part

  • @shadow_blader192
    @shadow_blader192 Pƙed 25 dny +1

    1:58 how do you see size and alignment of class? :)

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny

      idk just visual studio tells me, maybe it is the productivity powertools extension that I have but I think it is just a visual studio feature

    • @shadow_blader192
      @shadow_blader192 Pƙed 25 dny

      @@lowlevelgamedev9330 ok thanks 👍

    • @somedudenamedanthony
      @somedudenamedanthony Pƙed 25 dny

      That's provided by a Linter/LSP like Intellisense or clangd.
      (Finding the size of a structure of class.)
      Just use the (sizeof) keyword/function.
      -It's not hard to do the math yourself if you know the size of element the class is holding.-
      -Lets say you have a "Position2D" or "Point2D" class, it obviously needs to numbers to represent the coordinates, so 2 integers/floats (4 bytes * 2 elements).-
      -You might also want a constructor, in this example we'll treat them like function pointers, which on a 64-bit architecture is 8 bytes (a.k.a. a long pointer.)-
      -That's 16 bytes, not including the default class functions that modern C++ provides.-
      Finding the padding is near impossible to do programmatically as it's determined by the compiler.
      (This is why clangd and Sonar Lint suggest you state the padding of each element in a structure.)
      This is all from my understand(ing), I might be wrong so it's best to do your research.

    • @shadow_blader192
      @shadow_blader192 Pƙed 25 dny

      @@somedudenamedanthony why tf you wrote all that. I goggled it, I update visual studio. Will test it later

  • @drominitoketchup
    @drominitoketchup Pƙed 16 dny +1

    I always get a crisis when I can't use a stack.

  • @devu4740
    @devu4740 Pƙed 24 dny

    When i did texture manager for my little doom like engine because of memory leaks everyone called me stupid. But look at me now i was stupid but at least solution was smart.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 24 dny

      lol that's how top gamedevs do it in game dev. If you look at top gamedev programmers that's what they talk about and they don't use unity they make unity :))

  • @zeez7777
    @zeez7777 Pƙed 23 dny

    6:43 The index also gets invalidated, so i dont really see the benefit of this tip.
    Sure on most cases you'll save 4 bytes on 64bit cause the pointer is 8bytes and your int textureIndex would be enough for any game and is only 4.
    Apart from that, you're passing in the texturemanager and then do a read with the index.
    That still boils down to reading the underlying pointer since your std::map/unordered_map is heap allocated.
    So it my mind that is the same speed, maybe even slower. Correct me if im wrong though.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 23 dny +1

      so for the first thing, for example there are 5 players each one with a skin, and they can change. The index won't be invalidated, there are always 5 players, the skin can. That was the case that I was thinking about. If the index can get invalidated you would make sure to check for that of chourse. Also for the second thing I was thinking about sending the gpu id directly, like sending the opengl id, but it doesn't matter, the speed is the same roughly but I mentioned that it can be even faster to make my point very clear.In practice it boils down to how the compiler optimizes it and it is the case that for this thing it can be slightly faster or slower but very small difference

  • @Spartan322
    @Spartan322 Pƙed 25 dny +5

    It boggles my mind how many people keep insisting that you need to often deal with memory management in C++, like in almost every case I've observed, if you're managing memory directly, you should be using a container of some sort, or you should be using the stack. There are even only a limited set of reasons to deal with a raw pointer directly without managing it. Ownership semantics with smart pointers even support dynamic arrays now, so why would you never not use them? Probably because people don't bother the learn C++ and just keep doing things the C way.

    • @user-mm9jy8mz1g
      @user-mm9jy8mz1g Pƙed 4 dny

      at that point you might as well just use java or c# đŸ€Ą

    • @Spartan322
      @Spartan322 Pƙed 4 dny

      @@user-mm9jy8mz1g You don't know what a garbage collector is do you? C++ ownership semantics don't need a GC, you don't need a GC if you use RAII, unique_ptrs are literally the same performance as manually performing the allocation, so unless you're claiming that C/C++ allocations are indistinguishable in performance to Java or C#, that's a self-clown comment. (technically the unique_ptr may be able to be more performant cause there is nothing actually preventing SBO, I don't recall of any implementation that does that, but they're technically allowed to)

    • @Spartan322
      @Spartan322 Pƙed 4 dny

      @@user-mm9jy8mz1g You need to learn what a GC is. C++ ownership semantics don't need a GC, RAII invalidates the need for a GC, unique_ptrs are literally the same performance as manually performing the allocation, so unless you're claiming that C/C++ allocations are indistinguishable in performance to Java or C#, that's a self-clown comment. (technically the unique_ptr may be able to be more performant cause there is nothing actually preventing SBO, I don't recall of any implementation that does that, but they're technically allowed to)

    • @Spartan322
      @Spartan322 Pƙed 4 dny

      @@user-mm9jy8mz1g You need to learn what a GC is. C++ semantics don't need a GC, RAII invalidates the need for it, unique_ptrs are literally the same performance as manually performing the allocation, so unless you're claiming that C/C++ allocations are indistinguishable in performance to Java or C#, that's a self-clown comment. (technically the unique_ptr may be able to be more performant cause there is nothing actually preventing SBO, I don't recall of any implementation that does that, but they're technically allowed to)

  • @sakamocat
    @sakamocat Pƙed 25 dny

    about allocating on the heap, inst it useful for class dependency management?
    like, hear me out... usually i have a codebase that only uses makefiles and very frequent OOP (don't ask why, i just don't have patience to learn CMake), and by doing so, i frequently encounter problems with changing a certain class to add a new member causing me to recompile the entire project only to make the dependant classes work accordingly, because if i don't, i can start modifying data that i shouldn't be or just cause some really "undebuggable" issues. so my usual solution is to abstract each member with a getter and a setter function, so i don't have to worry about using the . or the -> operator in raw members and alignment, since it will be dealt with when compiling the single c++ file.
    however i do understand where you come from... nice tips!

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny

      that doesn't really sound good :))) and I also don't get how what you are describing has to do with the heap

    • @sakamocat
      @sakamocat Pƙed 24 dny

      @@lowlevelgamedev9330 if i use the stack, the size for structs and classes will be fixed, like:
      struct A {};
      struct B { A a; int bar; };
      So, ignoring the class optimization thing that some compilers do, and considering that A and B are on different headers and .cpp files respectively, if I change A to this:
      struct A { int foo; };
      For the .cpp file of B, it still thinks that A has not changed, but A has changed, so A.foo becames the same as B.bar, making some really weird bugs and eventually leading to UB.
      My fix is to defined the heap allocator for each class inside the .cpp files and wrap foo and bar with getters and setters

  • @raykoranteng4667
    @raykoranteng4667 Pƙed 25 dny

    Doesn't not deallocating at the end of a program cause memory leaks and also the possibility to loose the data, just like if you force terminated the program in task manager?

    • @saniancreations
      @saniancreations Pƙed 25 dny +7

      No, none of those actions leak any memory. It it the job of the OS to ensure that all memory from a process is reclaimed, if it didn't do that your memory would be gone in no-time (a program crashed and couldn't free its memory? Another 20MB never to be recovered! Nah...). So when a program terminates, either normally or forcefully (like with taskmgr), the OS will reclaim any memory that the process had not yet freed. Therefore, freeing when you are about to terminate your program is pointless, you're doing work that the os is going to do anyway, and when the os does it, it quickly cleans all your memory in one go instead of slowly one object at a time, which is what your own code has to do. All of this is also why it is okay to prototype code with leaks, it's not possible to eat away at the memory in between re-compiles, stopping the exe wipes away all leaks.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny

      yes as the other comment suggested the os will clear everythingvery easily. Also most programs have leaks so it would have been a disaster if it didn't 😂😂

    • @raykoranteng4667
      @raykoranteng4667 Pƙed 25 dny

      @@saniancreations I'm still in college (so I'm still a learner), we did plenty of tasks with memory allocation in C, and they told us to always clear the memory after we stopped using it. If you don't deallocate before the program ends and you run it with fsanitizer or Valgrind it will tell you that you have memory leaks

    • @Spartan322
      @Spartan322 Pƙed 25 dny +2

      @@raykoranteng4667 That's because the expectation is that a memory leak is a bug in your program that had it been left running, would be unrecoverable memory without termination.

    • @saniancreations
      @saniancreations Pƙed 24 dny

      @@raykoranteng4667 Memory leaks are a problem so long as your application is running. When your program stops, all the leaks go away. If you have a program that runs for a long time or it performs a repeated operation, then not freeing memory is an issue because the memory usage accumulates over time, slowly growing bigger and bigger. _That_ is what you want to avoid. Most external diagnostic tools indiscriminately look at _all_ allocations, marking anything that is never freed as a leak. But not everything that isn't freed will cause your program to infinitely grow. For example, doing a one-time allocation at start-up and using it for the duration of the program will not grow your memory footprint over time. The only moment you need to free it is at the end, and in that case the OS can do it for you.
      I like to image leaks as actual water: A single droplet is okay. Not a leak. A glass of water is okay. Still not a leak. I can have a whole swimming pool in my house and that is still fine, because I deliberately put it there and it has a finite amount of water in it. But a _leak_ is a hole in your program, water pours out the hole indefinitely, until your house is flooded. That's a problem.
      But, "not freeing" is something you need to be careful with. If you _think_ you only allocate something once, but that code gets executed _again_ every so often through a weird edge-case, then you still have a leak on your hands, then your usage _will_ grow over time. So as a rule of thumb it is generally recommended to free all memory, just to be safe and to prevent stupid mistakes.
      In practice, for many small programs that have a clear beginning and end, not freeing memory is actually fine, it gets some memory to do a job, then it terminates and all the memory is cleaned up no-problemo. Pouring some water on the floor isn't a big deal if your house is about to get demolished. But if you have a large loop that can run an unknown number of iterations, you could end up pouring a thousand+ buckets of water on the floor, and you'll drown before the demolition crew gets there.

  • @xd-hood-classic
    @xd-hood-classic Pƙed 23 dny

    which font did you use in the video?

  • @TheOptimus1200
    @TheOptimus1200 Pƙed 25 dny +3

    Basically, if you need to deal with memory allocation:
    1. Thou shalt call one 'delete' for every 'new'.
    2. Separate memory management tasks from other tasks.
    3. The "big 3" for a class with memory allocation to avoid crashing: copy constructor and assignment operator for deep copies, and destructor for cleanup.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny

      I mean 1 is an oversimplification, if you have a simple system you do that or raii, but for a complicated system it won't look as clean

    • @palapapa0201
      @palapapa0201 Pƙed 23 dny +1

      1. Just use smart pointers

  • @TeofilBejan-lg2rt
    @TeofilBejan-lg2rt Pƙed 7 dny

    You can just use smart pointers and you're done

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 7 dny

      well as mentioned in the video, they won't help you with difficult cases. You can't manage gpu memory like that for example

  • @carmelo5991
    @carmelo5991 Pƙed 23 dny

    2:50 es mejor usar std::make_unique si no vas a inicializar el std::unique_ptr con un destructor personalizado es mejor porque:
    - Sigue la regla de evitar el uso de "new" porque actualmente hay mejores opciones para manejar la memoria
    - "auto p = std::make_unique()" es mĂĄs corto y conciso que "std::unique_ptr p(new Player{})
    - std::unique_ptr estĂĄ implementado para ser seguro ante las excepciones

  • @kenarnarayaka
    @kenarnarayaka Pƙed 20 dny

    Never understood why heap allocation was used so much, still don't and my projects run fine
    I should really learn though

  • @RawFish2DChannel
    @RawFish2DChannel Pƙed 25 dny +1

    Question: How to avoid memory leaks when allocation new objects?
    Answer: Don't
    👍
    Also you can allocate stuff upfront and use them as needed

  • @dimi144
    @dimi144 Pƙed 3 dny

    7:21 this is not good advice, if it takes long for your program to do deallocations, simply hide your window to do it. It won't get in the user's way and you'll also be 100% sure that no resources were leaked

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 3 dny

      why dealocate in the first place, there is no such thing as leaking anything once you close your program. RAM VRAM loaded dlls handles, everything is cleared by the os when you exit, and it is also faster

  • @pedropena6789
    @pedropena6789 Pƙed 24 dny

    Man this is amazing, you could probably make a prototype game like mount and blade warband with your engine.

    • @user-mm9jy8mz1g
      @user-mm9jy8mz1g Pƙed 4 dny

      he is also one person, so maybe in 30 years when the engine is finished... for now the only thing he could do is little examples. (like an image of single cube rendered in a minimalistic way)

  • @GabrielBON-fu4ow
    @GabrielBON-fu4ow Pƙed 17 dny

    malloca 🧐

  • @moonyl5341
    @moonyl5341 Pƙed 2 dny +1

    -fsanitize=address

  • @blkkatana
    @blkkatana Pƙed 25 dny

    4:54 Isn't that called... handles?

  • @Volt-Eye.
    @Volt-Eye. Pƙed 25 dny

    This vdo has enlighten me that I don't need Cpp for my game programming.
    Its just Good for Backend
    Who uses Cpp for Platformer

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny +3

      what :) who uses cpp for backend. Cpp is used for gamedev very often

    • @Volt-Eye.
      @Volt-Eye. Pƙed 25 dny

      @@lowlevelgamedev9330 by Backend I mean Core of the engine not the cream part of a Game.
      Ofcourse you might have a F 35 but who uses it to go to grocessory store.
      Just use a LMEV

  • @u9vata
    @u9vata Pƙed 25 dny

    Very well put together video - I literally program nearly the same way, just with a bit more raii and also changing some of your rare usage of "new" keyword with malloc in my case for arrays - but as you point out: memory resources get so rarely hand-managed when done well that its a no-problem.
    This is also why I am not interested in rust - they solve a problem very complicatedly that with a good style one can easily solve themselves. Then rust fanboys compare newly written codes from them with hugely legacy decades old codebases with old style never looking like this to prove.... what exactly?

    • @nb94840
      @nb94840 Pƙed 24 dny +1

      Fully agree, for me its the same

  • @perfectionbox
    @perfectionbox Pƙed 18 dny +1

    just deallocate whatever you allocate, duhh 🙄

    • @user-mm9jy8mz1g
      @user-mm9jy8mz1g Pƙed 4 dny

      people just like having things being handled for them... and then also claim that they make everything from "scratch" at this point they all might as well just use java or c# lol.

  • @flyingsl0ths
    @flyingsl0ths Pƙed 24 dny +3

    all these memory leaks are from people using c with classes not c++

  • @lukasjetu9776
    @lukasjetu9776 Pƙed 25 dny

    hello

  • @anthonysteinerv
    @anthonysteinerv Pƙed 22 dny

    Well, I hate checking for iterator invalidation, plus vector is heap only, so bragging about not using smart pointers even with make_unique or make_shared is kind of crazy. Plus, I'm like 70% sure that vector is not actually guaranteed to be allocated contiguously. But yeah, temporary and arena allocators are great techniques, and in fact memory management systems are kind of crazy in big game engines.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 22 dny

      well the point is not to have leaks so I don't care that vector is also heap, I just care that it doesn't leak like an unique pointer. Also yes the vector is 100% guaranteed to be contiguously.

  • @romangeneral23
    @romangeneral23 Pƙed 23 dny +1

    So you are coding in C but saving the file as a .cpp ? Then code in C

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 23 dny +2

      I do use vectors, just because cpp has a feature it doesn't mean I have to do it. There are modern languages like zig that have no private variables or no exceptions

    • @romangeneral23
      @romangeneral23 Pƙed 23 dny

      @@lowlevelgamedev9330 Right and one day zig will replace C. I enjoy your videos for the record they are awesome and well done. But please understand something on this level of advise. There are two programming languages. There is C, and there is C++. There is no such thing as C/C++ programming language. These tricks for memory leaks and all that is all C language stuff and not C++. This causes confusion to new comers who want to learn C++. If you going to use C++ but code in C style then just code in C. If there is a feature of C++ you like then use it properly. This makes the codebase all over the place and introduces code rot.
      Zig for the record is awesome and I cannot wait for its 1.0 release!

    • @oracleoftroy
      @oracleoftroy Pƙed 23 dny +1

      ​@@romangeneral23 Sorry, but what makes this code "C style" rather than C++ style? Using automatic resource lifetime management with things like the stack, vector, unique_ptr, etc is very much a C++ thing and one C can't do and it's community has resisted adding.
      If you mean making classes and/or using inheritance, it is by no means C++ style to force those into a design without a reason. Same with exceptions. Same with new. Same with every other feature.
      I think you have the misconception. C++ is very much _not_ about forcing you into a particular style or design, but about giving you tools to meet the needs of your particular application. Nothing about the language forces you to use something you don't need.

    • @insentia8424
      @insentia8424 Pƙed 6 dny +1

      @@oracleoftroy The stack is not a C++ thing, nor is a it a thing C has no access to. It's specific to the OS and architecture you are programming for.

    • @oracleoftroy
      @oracleoftroy Pƙed 5 dny

      @@insentia8424 Automatic resource management that is based on the stack absolutely is a thing in C++. Look up RAII and how destructors work if you aren't familiar with it.

  • @ItsBaffledd
    @ItsBaffledd Pƙed 25 dny +1

    - Look at me I dont use new anywhere really
    - Oh, btw I just use containers and obfuscate the new calls and allocations, dw shh

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny +1

      well yes but that means I don't have leaking problems, what were you expecting, getting rid of leaks magically?

  • @W0lfCL
    @W0lfCL Pƙed 23 dny +1

    Simple trick: you don't deal with memory leaks, you just but more RAM

  • @williamdrum9899
    @williamdrum9899 Pƙed 25 dny +2

    It used to be so easy. Nowadays computers are so complex nobody knows how they really work so we end up confusing ourselves further

    • @rodrigomontebello
      @rodrigomontebello Pƙed 25 dny

      I think it depends on the programming language, for example, C and C++ always had problems with memory allocation and pointers. But newer languages have other big issues. So you have to find the best fit and dive into it.

    • @williamdrum9899
      @williamdrum9899 Pƙed 25 dny +1

      @@rodrigomontebello I firmly believe that C is the reason pointers are confusing. In assembly they're not that hard to grasp

    • @niggacockball7995
      @niggacockball7995 Pƙed 24 dny

      @@williamdrum9899 people are confused at pointers because they only learn what it does, not why it does that. so they dont understand why would they use them

  • @skeleton_craftGaming
    @skeleton_craftGaming Pƙed 25 dny

    Except for using smart pointers are semantically equivalent to using raw pointers correctly. Except for you. Don't have to actually generate the code to use them correctly yourself? [That is to say your code is probably buggy because you're not atomically reference counting your allocated pointers; there is a reason they do that in the standard library] And you're probably also actually leaking memory to the operating system [Windows really doesn't like you using opengl so they don't consistently free on exit vram allocated for opengl/Vulcan...] Which is the only explanation for your application taking longer to close when you actually properly free your memory which you should always do without question... Especially if you're only making five calls to new anyway.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny

      um I didn't really understood your comment but windows without question will free all the resources and it will do it quickly :))

    • @skeleton_craftGaming
      @skeleton_craftGaming Pƙed 25 dny

      My main point is that there is no valid reason to use the new keyword outside of a constructor, and even then you should tread carefully. And also no windows does not consistently free on exit. I've had, as recently as today, programs crash and stay resident and not boot because of that..

    • @skeleton_craftGaming
      @skeleton_craftGaming Pƙed 25 dny

      But to clarify exactly what I said, using the standard template library's unique_ptr type generates the exact same code as T:: operator new assuming you do not copy... And if you do copy, you are probably introducing bugs by not implementing a reference counter

  • @marks_shot
    @marks_shot Pƙed 25 dny

    cmak

  • @santitabnavascues8673
    @santitabnavascues8673 Pƙed 25 dny

    Don't go Java. Everything is a pointer there. And have memory leaks.
    The stack is limited in size, all of your static data has to fit in it, and depending on the compiler it can be as little as 16kb to as much as 16mb, so there is also the risk of a stack overflow... and... you don't know how many times they slip in "new" for you in your new-less code, sorry to break the bubble... But that's the RAII paradigm for you.

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny

      can you have leaks in java? I didn't know that, if you have some details I would love to hear them so you can tag me on my discord đŸ’ȘđŸ’Ș

    • @Spartan322
      @Spartan322 Pƙed 25 dny

      @@lowlevelgamedev9330 Not unless the JVM GC has a memory leak. The GC ensures there are no memory leaks.

    • @santitabnavascues8673
      @santitabnavascues8673 Pƙed 25 dny

      @lowlevelgamedev9330 it is a myth Java doesn't leak. You simply have to mess the references to an object by not deleting appropriately containers or other kind of faulty memory management czcams.com/video/Ml-jZipUzPk/video.html

    • @diadetediotedio6918
      @diadetediotedio6918 Pƙed 24 dny

      ​@@Spartan322
      I mean, "leak" in the sense that it is lost memory you can't have (usually), but you can still "leak" memory in some sense by not removing all references of it from memory (like having some pesky static delegate somewhere or etc, even if it is a sign of smelly code).

    • @Spartan322
      @Spartan322 Pƙed 24 dny

      @@diadetediotedio6918 That's not a leak, you might be erroneously retaining a memory location for your application, but memory leaks are quite well defined and without a memory leak in the JVM GC, it literally cannot leak, if that is a leak then any runtime static data is always a memory leak which is nonsense, an existing reference you could still access is not a leak, a memory leak must lose all references in the program and thus can only be cleaned up by OS upon termination of the program. (as without that memory reference the program can no longer recognize locate that memory to be manually deleted)

  • @melficexd
    @melficexd Pƙed 23 dny

    I never use "new". Not even once.
    I use malloc. đŸ€Ł

  • @rodrigomontebello
    @rodrigomontebello Pƙed 25 dny

    It's funny how nowadays we are slowly going back to procedural programming and leaving OOP

    • @niggacockball7995
      @niggacockball7995 Pƙed 24 dny

      yeah function pointers within structs is all you need actually

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 24 dny +1

      well it's normal. Procedural is both how people think and also how the computer thinks so idk who is thinking that functional programming is good :))

    • @diadetediotedio6918
      @diadetediotedio6918 Pƙed 24 dny +1

      The limits of your language are really the limits of your world.
      And also, one youtuber is not a representative of "we" (assuming you mean programmers in general) and it certainly is not a representative of something we should be doing by itself, I see comments like this in almost any video where someone is using something even remotely close to what other people used in the past, even if the thing itself evolved in some way, it is surely "funny".

    • @tychoides
      @tychoides Pƙed 22 dny

      @@lowlevelgamedev9330 I found oop useful in cases where where you are modeling stuff properties and behavior, like video games or controlling devices. But I avoid class polymorphism like inheritance as most hierarchies are just arbitrary design decisions that are often bad decisions. Rust "objects" are ok. Mostly I do procedural even in Python. Functional programming is great for processing data, specially in high level languages. Rust functional features for example are ok. Pure functional languages are not worth the pain, as their obsession with avoiding side-effects and immutability is stupid in practice.

  • @notarandom7
    @notarandom7 Pƙed 25 dny +4

    the last tip is horrible. not deallocating memory is just generally bad practice and should be avoided. the amount of time it takes to do that doesn't take that long and if you have so much memory allocated that it takes a while to close you just did something completely wrong

    • @lowlevelgamedev9330
      @lowlevelgamedev9330  Pƙed 25 dny +8

      have you ever waited for a program to close? it happened to me. So tell me why should I dealocate the memory for textures that I use for my entire game? That's just waisted work. It is true that it probably won't take long but you don't have any reason to do it either

    • @notarandom7
      @notarandom7 Pƙed 25 dny

      @@lowlevelgamedev9330 because you're closing your program, you don't need the texture anymore

    • @SianaGearz
      @SianaGearz Pƙed 25 dny

      @@lowlevelgamedev9330 I mean if it takes that long to deallocate everything, you are almost guaranteed abusing malloc somewhat fierce with way too many small allocations. You have yourself shown strategies here to stop doing that. Sure you can just leave everything be on exit but that precludes the use of leak analysis tools and the like, which is not ideal.

    • @tiranito2834
      @tiranito2834 Pƙed 25 dny

      ​@@lowlevelgamedev9330 Exactly. The only reason one would consider deallocating everything at the end would either be for correctness sake or because of the possibility of running that code on a system that doesn't free memory after a process is closed. To date, there is literally not a single active operating system that works like this, so... you are 100% correct. Not deallocating things that are going to be static is pretty much standard in the industry and is guaranteed to work basically everywhere. I mean, after all, what exactly is the difference between allocating a static buffer at compile time and allocating a heap buffer during runtime at the start of your program? the OS follows the exact same steps when loading the program and assigning the memory segments to the address space of the program. The only difference is that one is a static buffer with a size known at compile time, and the other is a static buffer with a size known during runtime (useful for loading files that can be modified, such as textures or any other assets).
      Besides... when you deallocate, your program is going to take longer between all the sleeping that the OS is going to put it through while its deallocating the reserved memory. Just closing the process allows the program to shut down visually for the user and then the OS can do the cleanup afterwards without having to make the end user wait any time for the program to shut down. This is just a common practice in the games industry, and one of the few practices that are actually good. I can understand people not liking it because it feels dirty, but it is still correctly exploiting the inner workings of the systems where the code will run, so...

    • @ohwow2074
      @ohwow2074 Pƙed 25 dny +8

      Not deallocating memory is fine. Not closing a file or socket is not fine.

  • @Kyoz
    @Kyoz Pƙed 23 dny

    đŸ€