假设我有以下代码:
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;
}
我用gcc尝试了它并且它显然有效但我认为它不是一个有效的程序,因为从“foo_wrapper”传递给“foo”的“Data”引用可能无效,因为传递的对象的析构函数可能在foo完成之前被调用执行(异步执行)。虽然我不删除数据(m_arr)但仍然在调用析构函数时对象引用会发生什么?
C ++(gcc)编译器是否只调用析构函数。例如,当调用对象“d”的析构函数时,它是否重新定位对象“d”的内存分配并将“d”设置为某个无效引用?
答案 0 :(得分:1)
取决于数组的初始化方式。如果你在堆栈上初始化它,那么这是undefined behavior
,因为如果foo()
是异步的,那么在foo()
完成之前可以销毁数组。但是如果它在堆上分配,那么如果你删除foo中的数组,或者在foo调用之后它是安全的。
但使用std::shared_ptr更安全。这是完美的管理 异步调用之间的指针。
答案 1 :(得分:1)
在这种情况下,传递给Data
的{{1}}实例(d
)将被放置在主线程的堆栈上 - 它肯定会被破坏并超出范围(例如,在foo()
返回之前,当主线程继续执行时可能重用。这是未定义的行为。即使分配没有被覆盖,也不应该使用被破坏的对象。
无论如何,您需要确保参数foo()
有效且在d
返回后才会被破坏。