5 ms·
Nearly all the time, memory management in C can be done using the following incredibly sophisticated pattern: create an object at the start of a function, and d
by fdej 13y ago
Nearly all the time, memory management in C can be done using the following incredibly sophisticated pattern: create an object at the start of a function, and destroy it at the end of the same function. Use constructor/destructor functions or macros to hide the details (such as whether the object is a plain fixed-size struct, or has to allocate additional variable-size memory on the heap). There are situations where this pattern cannot be used, but they can be made very rare in properly structured C code.
Finally, write unit tests and run them through Valgrind. That catches almost all memory-related bugs.
- dTal 13y agoYou cannot create objects in C. I tried to work out what you meant, but honestly I can't. Where do you put these "constructor/destructor" functions? In the global namespace? So you have structs, and functions that modify structs. How is this pattern different from the one we call "programming in C"?
- fdej 13y agoSure, structs and functions that modify structs are the bare mechanisms provided by C. From the higher-level point of view, structs may represent objects and a constructor is then just a piece of code (possibly implemented a function) that initializes a struct, and a destructor frees any memory it owns (if the struct does not contain any pointers, destroying it is just a no-op). Initializer and de-initializer might be better terms. There are certainly non-examples of this pattern (with legitimate uses, for sure, but they can be avoided as a general rule). One is global variables. Another is creating an object in one part of a program and destroying it in another (as opposed to the start/end of the same function or block), or worse, in multiple possible locations.
- antimagic 13y agoI can see where you're going with this, but I think you're being a little glib with the "nearly all the time" bit. There are large chunks of functionality that can't be written that way. The most obvious one is graphical objects, which are typically expensive to render. You can't be destroying / recreating them on the fly, the number of graphical elements in use changes radically over the lifetime of a typical graphical application, and you generally have an event loop, which means the only function that would keep the objects alive is at the top level of the event loop. I personally tend to look at malloc/free in the same way that I look at if statements. I generally consider code to be cleaner without them, so where possible I will avoid them, but sometimes that's not possible, which is why malloc / free (or if statements) exist.
- fdej 13y agoYeah, definitely a little glib. There are certainly prominent exceptions. Still, I think it's a valid general principle. At least, it works well enough for me, and I very rarely have to think consciously about memory management in C. But YMMV, different application domains, and all that.
- dllthomas 13y ago"The most obvious one is graphical objects, which are typically expensive to render." For me, in my current project, it's message passing between the low-latency thread and other threads.
- aidenn0 13y agoIt most notably does not work in the case of longjmp() which nethack uses a lot.