Suppose, I have the following code:
class Data
{
private:
int *m_arr;
int m_size;
bool m_deAlloc;
public:
Data(int *arr, int size): m_arr(arr), m_size(size), m_deAlloc(false) {}
~Data(){ if(m_deAlloc) delete[] m_arr; }
...
};
void foo(Data &d)
{
// uses d ...
}
void foo_wrapper(int *arr, int size)
{
Data d(arr, size); // should I create it as new Data(arr, size)?
foo(d); // asynchronous call...
} // ~Data() will be called but m_arr array will not be erased...
int main()
{
int *arr = new int[...];
...
foo_wrapper(arr,...); // internally calls foo asynchronously...
...
// wait for foo execution completion....
...
delete[] arr;
}
I tried it with gcc and it works apparently but I think it’s not a valid program as “Data” reference passed to “foo” from “foo_wrapper” can be invalid as destructor of the object passed might get called before foo has finished executing (asynchronous execution). Although I don’t delete data (m_arr) but still what happens with the object reference when destructor gets called?
Does the C++ (gcc) compiler just calls the destructor. For example when a destrutor for object “d” is called, does it relocate memory allocation for object “d” and set “d” to some invalid reference?
In this case, the
Datainstance (d) you pass tofoo()will just be placed on the main thread’s stack — it can certainly be destructed and out of scope (e.g. potentially reused as the main thread continues execution) beforefoo()returns. It is undefined behavior. Even if the allocation were not overwritten, you should not play with a destructed object.One way or another, you need to ensure the parameter
dis valid and not destructed until afterfoo()has returned.