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」に渡された「Data」参照が無効になる可能性があるため、有効なプログラムではないと思います。渡されたオブジェクトのデストラクタは、fooの実行が完了する前に呼び出される可能性があります実行)。データ (m_arr) は削除しませんが、デストラクタが呼び出されるとオブジェクト参照はどうなりますか?

C++ (gcc) コンパイラはデストラクタを呼び出すだけですか。たとえば、オブジェクト「d」のデストラクタが呼び出された場合、オブジェクト「d」のメモリ割り当てを再配置し、「d」を無効な参照に設定しますか?

4

2 に答える 2

1

この場合、渡されたDataインスタンス ( )はメイン スレッドのスタックに配置されるだけです。確実に破棄されて範囲外になる可能性があります (たとえば、メイン スレッドが実行を継続するときに再利用される可能性があります)。これは未定義の動作です。割り当てが上書きされなかったとしても、破壊されたオブジェクトで遊んではいけません。dfoo()foo()

dいずれにせよ、パラメーターが有効であり、afterfoo()が戻るまで破棄されないようにする必要があります。

于 2012-11-06T11:33:34.920 に答える
1

配列がどのように初期化されたかによって異なります。スタックで初期化する場合、これundefined behaviorfoo()非同期の場合、配列がfoo()終了前に破棄される可能性があるためです。ただし、ヒープに割り当てられている場合は、foo 内または foo 呼び出しの後に配列を削除しても安全です。

ただし、 std::shared_ptrを使用する方が安全です。非同期呼び出し間のポインターを管理するのに最適です。

于 2012-11-06T11:29:01.283 に答える