I'm working on a medium embedded application in C using OO-like techniques. My "classes" are .h/.c modules using data structs and function pointers structs to emulate encapsulation, polymorphism, and dependency injection.

Now, one would expect a myModule_create(void) function to come with a myModule_destroy(pointer) counterpart. But the project being embedded, the resources that are instantiated realistically should never be released.

I mean, if I have 4 UART serial ports and I create 4 UART instances with their required pins and settings, there's absolutely no reason to ever want to destroy UART #2 at some point during runtime.

So following the YAGNI (You ain't gonna need it) principle, should I omit the destructors? This seem extremely strange to me but I can't think of a use for them; resources are freed when the device powers-off.

  • 4
    If you don't provide a way to dispose the object, you are passing a clear message that they have "infinite" lifetime once created. If this makes sense to your application, I say: do it.
    – glampert
    Commented Jul 22, 2014 at 18:24
  • 4
    If you're going to go that far in coupling the type to your particular use case, why even have a myModule_create(void) function? You could just hard-code the specific instances you expect to use into the interface you expose.
    – Doval
    Commented Jul 22, 2014 at 18:25
  • @Doval I thought about it. I'm an intern using parts and bits of code from my supervisor so I'm trying to juggle with "doing it right", experimenting OO style in C for experience, and consistency with the company's standards.
    – Asics
    Commented Jul 22, 2014 at 18:30
  • 2
    @glampert nails it; I'd add that you should make the expected-infinite lifetime clean in the create function's documentation.
    – Blrfl
    Commented Jul 23, 2014 at 2:53

4 Answers 4


If you don't provide a way to dispose the object, you are passing a clear message that they have "infinite" lifetime once created. If this makes sense to your application, I say: do it.

Glampert is right; there is no need for destructors here. They would just create code bloat and a pitfall for users (using an object after its destructor is called is undefined behavior).

However, you should be sure that there is really no need to dispose of the objects. For instance, do you need to have an object for a UART that is not currently in use?


The easiest way I have found to detect memory leaks is to be able to cleanly exit your application. Many compilers/environments provide a way to check for memory that is still allocated when your application exits. If one isn't provided there's usually a way to add some code right before exiting which can figure it out.

So, I would certainly provide constructors, destructors and shutdown logic even in an embedded system that "theoretically" should never exit for ease of memory leak detection alone. In actuality, memory leak detection is even more important if the application code should never exit.

  • Note that this doesn't apply if the only time you do allocations is during startup, which is a pattern I'd seriously consider in memory constraint devices. Commented Aug 5, 2014 at 8:36
  • @Codes:There's no reason to limit yourself. While you may come up with the great design that pre-allocates memory at startup, when the people after you come along who aren't privy to this grand scheme or fail to see the importance of it, they'll be allocating memory on the fly and there goes your design. Just do it right and allocate/de-allocate and verify that what you implemented actually works. If you truly have a memory constrained device then what is typically done is to override the new operator/malloc and prereserve allocation blocks.
    – Dunk
    Commented Aug 6, 2014 at 19:22

In my development, which makes extensive use of opaque data types to foster an OO-like approach, I too wrestled with this question. At first, I was decidedly in the camp of eliminating the destructor from the YAGNI perspective, as well as the MISRA "dead code" perspective. (I had plenty of resource room, that wasn't a consideration.)

However... the lack of a destructor can make testing more difficult, as in automated unit/integration testing. Conventionally, each test should support a setup/teardown so that objects can be created, manipulated, then destroyed. They are destroyed in order to assure a clean, untainted starting point for thenext test. To do this, the class needs a destructor.

Therefore, in my experience, the "aint't" in YAGNI turns out be to an "are" and I ended up creating destructors for every class whether I thought I'd need it or not. Even if I skipped testing, at least a correctly designed destructor exists for the poor slob that follows me will have one. (And, to a much lesser value, it makes the code more reusable in that it can be used in an environment where it would be destroyed.)

While that addresses YAGNI, it does not address dead code. For that, I find that a conditional compile macro something like #define BUILD_FOR_TESTING allows the destructor to be eliminated from the final production build.

Doing it this way: you have destructor for testing/future reuse, and you satisfy the design objectives of YAGNI and "no dead code" rules.

  • Be careful about #ifdef'ing your test/prod code. It's reasonably safe when applied to a whole function, as you describe, because if the function is in fact needed, compilation will fail. However, using #ifdef inline inside a function is much riskier since you are now testing a different codepath from what is running in prod.
    – Kevin
    Commented Feb 2, 2018 at 23:13

You could have a no-op destructor, something like

  void noop_destructor(void*) {};

then set the destructor of Uart perhaps using

  #define Uart_destructor noop_destructor

(add the suitable cast if it is needed)

Don't forget to document. Maybe you want even

 #define Uart_destructor abort

Alternatively, special case in the common code calling destructor the case when the destructor pointer function is NULL to avoid calling it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.