C++ local stack allocated instance destructor

ChibiOS public support forum for all topics not covered by a specific support forum.

Moderators: RoccoMarco, lbednarz, tfAteba

Post Reply
hazelnusse
Posts: 77
Joined: Thu May 24, 2012 8:01 am

C++ local stack allocated instance destructor

Post by hazelnusse »

If I allocate an instance of a C++ class type on the stack inside of a thread function, it seems like the destructor for this instance will not be executed if the thread function calls chThdExit() instead of actually returning. The compiler won't know that the no instructions will be executed after chThdExit() so presumably all the destructor calls for locals won't be called. I can use a scope block to force the destructor to run, or I can put all my functionality inside of another function that does return and hence all the destructors of local stack objects will be called before returning.

The documentation writes:
a thread terminates by returning from its top level function or invoking a specific API


So presumably returning from my top level function or calling chThdExit() will both work equivalently? If I return instead of calling chThdExit(), does the return value the same meaning as the parameter passed to chThdExit()?

Thanks,
Luke
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: C++ local stack allocated instance destructor

Post by Giovanni »

Hi,

Returning from a function is the same of calling chThdExit(), the parameter is the same of return value.

Giovanni
hazelnusse
Posts: 77
Joined: Thu May 24, 2012 8:01 am

Re: C++ local stack allocated instance destructor

Post by hazelnusse »

If chThdExit() never returns, and the compiler doesn't know this (which it seems like it will not), doesn't this imply that the cleanup code for user defined types (i.e., class destructors) will not be run, since the compiler implicitly places this code at the end the function body? So

Code: Select all

return exitcode;
vs.

Code: Select all

chThdExit(exitcode)
would only be the same if all the local variables of the thread function have no destructor, i.e., built-in types or types which don't need to do anything special to clean up after themselves.

Specifically, here is a trivial made up example of what I am talking about:

Code: Select all

class foo {
  public:
    foo(int N) : data_ptr(new int[N]) {}
    ~foo() { delete [] data_ptr; }
  private:
    int * data_ptr;
};

msg_t thread_func(void *)
{
  foo f(10);
  chThdExit(0);  /* Never returns, hence ~foo() is never called, hence memory leak of 10 ints on free store */
  /* Code is placed implicitly here by the compiler to call ~foo(); but will never be executed because chThdExit never returns. */
}


if the call to chThdExit(0); was changed to return 0; then the implicit compiler generated calls to the destructor will be called and the memory will not be leaked. I'm not actually using new in my particular application, but I have some other cleanup code that needs to be called when a variable goes out of scope so I am pretty sure I need to use return, not chThdExit();

If I am missing something, let me know.

Luke
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: C++ local stack allocated instance destructor

Post by Giovanni »

Hi,

chThdExit() is equivalent to return but this does not include finalization code of course. I don't know any portable way to inform the compiler that the function does not actually return.

There are GCC extensions that allow to do that but I would not rely on those.

Giovanni
hazelnusse
Posts: 77
Joined: Thu May 24, 2012 8:01 am

Re: C++ local stack allocated instance destructor

Post by hazelnusse »

chThdExit() is equivalent to return but this does not include finalization code of course.


To me this means they are not equivalent. Equivalent would mean the exact same cpu instructions will be executed, but since destructors will not be called when using chThdExit(), the code with return will take a different path than the code with chThdExit(). Of course, this only applies to threads implemented in C++ which declare objects on the stack that have a non-trivial destructor.
MartinP
Posts: 35
Joined: Mon Apr 02, 2012 11:54 am

Re: C++ local stack allocated instance destructor

Post by MartinP »

Some extra braces { ... } should do the job in c++

Code: Select all

msg_t thread_func(void *)
{
  {
    foo f(10);
  } // Here the destructor will be called....
  chThdExit(0);
}


Martin
Post Reply