在析构函数(可能)被调用后使用对象引用

时间:2012-11-06 11:22:13

标签: c++ asynchronous concurrency constructor destructor

假设我有以下代码:

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”设置为某个无效引用?

2 个答案:

答案 0 :(得分:1)

取决于数组的初始化方式。如果你在堆栈上初始化它,那么这是undefined behavior,因为如果foo()是异步的,那么在foo()完成之前可以销毁数组。但是如果它在堆上分配,那么如果你删除foo中的数组,或者在foo调用之后它是安全的。

  

但使用std::shared_ptr更安全。这是完美的管理   异步调用之间的指针。

答案 1 :(得分:1)

在这种情况下,传递给Data的{​​{1}}实例(d)将被放置在主线程的堆栈上 - 它肯定会被破坏并超出范围(例如,在foo()返回之前,当主线程继续执行时可能重用。这是未定义的行为。即使分配没有被覆盖,也不应该使用被破坏的对象。

无论如何,您需要确保参数foo()有效且在d返回后才会被破坏。