4

メモリを再割り当てせずにオブジェクトをインプレースで置き換えることを目的としたコードに出くわしました。

static void move(void* const* src, void** dest) {
   (*reinterpret_cast<T**>(dest))->~T();
   **reinterpret_cast<T**>(dest) = **reinterpret_cast<T* const*>(src);
}

これは、オブジェクトが破棄されてから構築されずに割り当てられるため、私にはUBのように見えます。つまり、コピー割り当て(2行目のみ)または明示的に破棄(1行目)してから配置-新しいコピー構築を行う必要があります。割り当ての代わりに。

これは私には明白なバグのように見えますが、 boost :: spirit::hold_anycdiggins::anyとそれが基づいているオリジナルの両方にしばらくの間存在していたので私は尋ねるだけです。(私はBoost開発者のメーリングリストでそれについて尋ねましたが、応答を待っている間、それが本当に間違っている場合はローカルでこれを修正したいと思います。)

4

2 に答える 2

3

reinterpret_castが明確に定義されている(つまり、dest実際にはへのポインタへのポインタである)と仮定するとT、標準ではオブジェクトの存続期間の終わりを次のように定義します。

タイプTのオブジェクトの存続期間は、次の場合に終了します。

  • Tが自明でないデストラクタ(12.4)を持つクラス型の場合、デストラクタ呼び出しが開始されます。
  • オブジェクトが占有するストレージは、再利用または解放されます。

次に、glvalueで実行できることについていくつかの制限を与えます**reinterpret_cast<T**>(dest)

同様に、[...]オブジェクトの存続期間が終了した後、オブジェクトが占有していたストレージが再利用または解放される前に、元のオブジェクトを参照するglvalueを使用できますが、その方法は限られています。[...]次の場合、プログラムの動作は未定義です。

  • 左辺値から右辺値への変換(4.1)は、このようなglvalueに適用されます。
  • glvalueは、非静的データメンバーにアクセスするため、またはオブジェクトの非静的メンバー関数を呼び出すために使用されます。
  • glvalueは暗黙的に基本クラスタイプへの参照に変換されます(4.10)、または
  • glvalueは、最終的にcv char&またはcv unsigned char&に変換される場合を除いて、static_cast(5.2.9)のオペランドとして使用されます。
  • glvalueは、dynamic_cast(5.2.7)のオペランドまたはtypeidのオペランドとして使用されます。

強調が追加されました。

些細なデストラクタがあるためにオブジェクトがこの寿命後の状態にならない場合は、問題はありません。ただし、T重要なデストラクタを持つクラスタイプの場合、代入演算子はoperator=そのクラスのメンバー関数と見なされることがわかっています。このglvalueを介してオブジェクトの非静的メンバー関数を呼び出すと、未定義の動作が発生します。

于 2013-03-12T11:24:01.867 に答える
0

これは、オブジェクトが破棄されてから構築されずに割り当てられるため、私にはUBのように見えます。つまり、コピー割り当て(2行目のみ)または明示的に破棄(1行目)してから配置-新しいコピー構築を行う必要があります。割り当ての代わりに。

何も修正する必要はありませんが、このコードはさらに資格がなければ安全ではありません(ただし、使用されているコンテキストでは安全であることは確かです)。

のオブジェクトdestが破棄され、次に、のオブジェクトをバックアップしているメモリが、のオブジェクトsrcが存在していた場所にコピーされますdest。最終結果:1つのオブジェクトを破棄し、最初のオブジェクトが存在していた場所に別のオブジェクトの浅いクローンを配置しました。

コピーの割り当てのみを行う場合、最初のオブジェクトは破棄されず、リソースリークが発生します。

配置newを使用してメモリをdest設定することもできますが、セマンティクスは既存のコードとは大きく異なります(既存のオブジェクトの浅いクローンを作成する代わりに、まったく新しいオブジェクトを作成します)。新規配置とコピーコンストラクターの使用にも異なるセマンティクスがあります。オブジェクトにはアクセス可能なコピーコンストラクターが必要であり、結果がどうなるかを制御できなくなります(コピーコンストラクターは必要な処理を実行します)。

于 2013-03-12T11:20:38.547 に答える