2

独自のメンバーの1つへのポインターを含む単純なクラスがあります。

struct X {
    int val;
    int* pVal;
    X(int v) : val(v), pVal(&val) {}
}

X x(1);

私はこのようなコードを持っています:

void foo() {
    doStuffWith(x);
    x = X(2); // completely discard the old value of X, and start again
    doStuffWith(x);
}

xが再割り当てされたときに、戻り値の最適化が行われない場合x.pVal、一時のメンバーを無効に指すのではないかと心配しています。X(2)

これを修正するためのコピーコンストラクターを作成できることに気付きました。ただし、最初にメモリ内の適切な場所にオブジェクトを作成するのではなく、最初にコピーを実行するのは無駄に思えます。


ここで配置の新しい演算子を使用するのは合理的ですか?それとも、これはデストラクタに意図しない結果をもたらしますか?

void foo() {
    doStuffWith(x);
    new (&x) X(2); // completely discard the old value of X, and start again
    doStuffWith(x);
}
4

3 に答える 3

3

これを機能させる最も明白な (そしておそらく最も効果的な) 方法は、コピー代入演算子とコピー構築演算子を提供して、「正しいことを行う」ことです。これは一般的な順序で行われます。

struct X {
    int val;
    int* pVal;

    X(int v) : val(v), pVal(&val) {}   
    X(X const &other) : val(other.val), pVal(&val) {} 

    // pVal was already set by ctor, so just ignore it:
    X &operator=(X const &other) { val = other.val; return *this; }

    // and allow assignment directly from an int:
    X &operator=(int n) { val = n; return *this; }
};

その後、コードの残りの部分は、X破損を防ぐためにフープをジャンプすることなく、オブジェクトをコピー/割り当てることができます。

于 2013-03-14T15:07:23.677 に答える
1

いいえ

の古い値を破壊することはありませんxが、デフォルトのコピー代入演算子もあなたが望むことをしません。

于 2013-03-14T14:53:54.747 に答える
-1

X のデストラクタが new を配置する前に呼び出される場合、私にとっては非常に受け入れられる解決策のようです。デストラクタが実際にクラスに指定されていなくても、構文的には許可されています。

struct X {
  int val;
  int* pVal;
  X(int v) : val(v), pVal(&val) {}
};

X x(1);

void foo() {
  doStuffWith(x);
  x.~X();
  new (&x) X(2); 
  doStuffWith(x);
}

この形式では、任意のオブジェクトに対してメモリを再利用する正しい方法です (ただし、オブジェクトの ctor がスローできない場合のみ! そうしないと、プログラムのシャットダウン時に UB が発生する可能性があります。つまり、デストラクタの二重呼び出し)。

実際、非配列形式の配置 new から渡されて返されるポインターの同等性は、標準によって保証されています。

18.6.1.3 配置フォーム

...

void* operator new(std::size_t size, void* ptr) noexcept;

戻り値: ptr.

備考: 意図的に他のアクションを実行しません。

(そして、void* への変換の結果と同じポインター型への変換の結果も、ソース ポインターと同じであることが保証されます)

ただし、クラスの不適切な使用を避けるには、コピー割り当てとコピーコンストラクターを定義するか、このクラスをコピー不可として宣言する方が安全です (削除されたものを使用)。

そして、最後の (コピー不可能な) ケースだけが、placement new を使用する理由と見なされる場合があります。

一般的な使用のために新しい配置を促進することにはほど遠いですが、それはオブジェクト メモリを直接再利用する意図を表し、最適化に依存していません。もちろん、コピーコンストラクターとコピー代入はより安全ですが、この意図を正確に表現しないでください。実際には「コピー」は必要ありません。古いオブジェクトの代わりに新しいオブジェクトを構築する必要があります。

于 2013-03-14T15:22:56.047 に答える