4

割り当てられたメモリの大きなチャンクと多くのプリミティブ型のメンバーへのポインタを保持するクラスがあります。私はmoveコンストラクターに頭を悩ませていますが、これはそれを使用する絶好の機会だと思います。明らかに、ポインタは上に移動する必要がありますが、プリミティブを使用するのが良い場合はidkです。

以下は、クラスの考案された例です。

class Foo {
private:
  long m_bar = 1;
  /* 20+ similar members */
};

それらを移動可能にするには、動的に割り当てる必要があります。

class Foo {
public:
  Foo(Foo && rhs) : m_bar(rhs.m_bar) { rhs.m_bar = nullptr; }
  ~Foo() { delete m_bar; }
private:
  long *m_bar = new long{1};
};

私の質問は、ヒープに割り当てるオーバーヘッドは、移動セマンティクスによってもたらされるパフォーマンスの向上を無効にするのでしょうか?

4

3 に答える 3

6

どちらかといえば、このように各メンバーを割り当てるヒープは遅くなると思います。初期のヒープ割り当てに加えて、構築時にのみ実行され、ヒープ上の多くの小さな非連続データメンバーへのポインターを保持することは、CPUキャッシング戦略ではうまく機能しません。

一部のクラスは、ヒープに割り当てられた大きなメモリビット(たとえば、std :: string)を持っているため、非常にうまく機能します。あなたの場合、各ポインタの移動は、小さいデータ型の移動と同じくらいの費用がかかります。これがより高速であることがわかる唯一の方法は、ヒープが割り当てられたクラス/構造体(おそらくunique_pointerを保持している)で小さいデータメンバーをラップし、単一のポインターの移動を介してそれらすべてを移動する場合です。

とはいえ、これは時期尚早の最適化のケースである可能性が非常に高いです。コードを実際に機能させて、クラスにさらに複雑な移動セマンティクスを実装すると、コードのパフォーマンスが本当に向上する可能性があることを確認することをお勧めします。

于 2012-11-19T15:19:46.007 に答える
2

移動セマンティクスは、オブジェクトの移動がコピーよりも高速である場合にのみ高速になります。あなたの例では、それは真実ではありません。ロングのコピーは、ポインタをロングにコピーするのと同じ速度である必要があります。個々のメンバーを動的に割り当てることによって移動セマンティクスを追加すると、速度が上がるのではなく、ほぼ確実に速度が低下します。

より高速な移動コンストラクターをもたらす可能性があるのは、PIMPLイディオムを使用することです。すべてのメンバーを含む1つのクラスを動的に割り当て、メインクラスにはそのクラスへのポインターのみが含まれます。次に、moveコンストラクターが実行する必要があるのは、ポインターを実装クラスにコピーすることだけです。

于 2012-11-20T17:33:46.907 に答える
1

プリミティブがポインタよりも大きくも(どういうわけか)コピーするのに費用がかからない場合、それを動的に割り当てることは単なる追加費用です。

オリジナルを無効にすることもできますが、ポインターは必要ありません。

于 2012-11-19T15:11:28.853 に答える