3

假设,我有以下代码:

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”的“数据”引用可能是无效的,因为传递的对象的析构函数可能在 foo 完成执行之前被调用(异步执行)。虽然我没有删除数据(m_arr),但是当调用析构函数时对象引用仍然会发生什么?

C++ (gcc) 编译器是否只调用析构函数。例如,当调用对象“d”的析构函数时,它是否会重新分配对象“d”的内存分配并将“d”设置为某个无效引用?

4

2 回答 2

1

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

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

于 2012-11-06T11:29:01.283 回答
1

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

一种或另一种方式,您需要确保参数有效并且在返回d之后才被破坏。foo()

于 2012-11-06T11:33:34.920 回答