5

戻り値の最適化 (RVO と NRVO の両方) に関する今日のコンパイラの高品質を考慮すると、ムーブ コンストラクターとムーブ代入演算子の追加を開始することが実際にどのようなクラスの複雑さに意味があるのか​​疑問に思っていました。

たとえば、このreally_trivialクラスの場合、ムーブ セマンティクスは、RVO および NRVO がそのインスタンスをコピーするときに既に提供しているもの以上のものを提供できないと想定しています。

class really_trivial
{
    int first_;
    int second_;

public:

    really_trivial();
    ...
};

このsemi_complexクラスでは、ためらうことなくムーブ コンストラクターとムーブ代入演算子を追加します。

class semi_complex
{
    std::vector<std::string> strings_;

public:

    semi_complex(semi_complex&& other);
    semi_complex& operator=(semi_complex&& other);
    ...
};

では、移動コンストラクターと移動代入演算子を追加することは、どのくらいの量で、どのような種類のメンバー変数で意味をなすのでしょうか?

4

5 に答える 5

9

最適化の側面を完全に除外したとしても、純粋にセマンティックな理由からすでに意味があります。クラスがコピーを実装しない/実装できない場合を想像してみてください。たとえばboost::scoped_ptr、コピーすることはできませんが、移動することはできます!

于 2011-01-18T13:00:14.093 に答える
7

すでに与えられた優れた回答に加えて、いくつかの将来の見通しに関する詳細を追加したいと思います。

最新のC++0xドラフトには、ムーブコンストラクターとムーブ代入演算子を自動的に生成するための新しいルールがあります。このアイデアは完全に新しいものではありませんが、最新のルールは2010年10月以降ドラフトに含まれているだけであり、コンパイラーではまだ広く利用できません。

クラスにユーザー宣言のコピーコンストラクター、コピー割り当て演算子、移動コンストラクター、移動割り当て演算子、およびデストラクタがない場合、コンパイラーはデフォルトの移動コンストラクターと移動割り当て演算子を提供します。これらのデフォルトの実装は、単にすべてをメンバーごとに移動します。

移動メンバーを明示的にデフォルト設定することもできます。

semi_complex(semi_complex&&) = default;
semi_complex& operator=(semi_complex&&) = default;

そうすると、コピーコンストラクタとコピー代入演算子を明示的に指定またはデフォルト設定しない限り、コピーセマンティクスが暗黙的に禁止されることに注意してください。

密接に関連する最新の変更:クラスに明示的なデストラクタと暗黙的なコピーメンバーがある場合、それらのメンバーの暗黙的な生成は非推奨になりました(明示的なデストラクタがある場合、委員会は暗黙的なコピーの生成を削除したいと考えています。ただし、下位互換性のためにできません)。

したがって、要約すると、デストラクタを宣言するときはいつでも、コピーメンバーと移動メンバーの両方を明示的に宣言することを検討する必要があります。

于 2011-01-23T19:34:24.423 に答える
5

通常、クラスがある種のリソースを保持している場合、移動は理にかなっています。コピーにはそのリソースのコピーが含まれ、移動には含まれません。最も簡単な例は、動的に割り当てられたメモリです。ただし、コピーの場合と同様に、コンパイラが移動コンストラクタと移動演算子を自動的に生成することに注意してください。

于 2011-01-18T12:58:13.243 に答える
5

経験則として、(条件付きで) 動的に割り当てられたメモリを保持するメンバー変数がある場合は常に、移動コンストラクターを追加します。その場合、既存のメモリを使用し、移動元に必要な最小限の割り当てを与えて、機能できるようにする (つまり、破棄する) と、多くの場合安価になります。メンバー変数の量はそれほど重要ではありません。動的メモリを含まない型の場合、それらをコピーするか移動するかで違いが生じる可能性は低いためです (移動コンストラクターでさえ、あるメモリ位置から別のメモリ位置に何らかの形でコピーする必要があります)。

したがって、移動のセマンティクスは理にかなっています。

  • 動的メモリ割り当てが関係しています
  • move は、1 つ以上のメンバー変数に対して意味があります (つまり、これらの変数は、どこかで動的割り当てを伴うことを意味します)。
于 2011-01-18T12:49:29.923 に答える
2

コンパイラによって自動的に行われる可能性のあるものに関係なく、次のように言います。

  • いずれかのメンバーが意味のある有益な移動セマンティクスを持っている場合、そのクラスにもこの移動セマンティクスが必要です。(→std::vectorメンバー)
  • コピー時に動的割り当てが含まれる場合、移動操作は理にかなっています。

別の言い方をすれば、move が copy よりも効率的に何かを実行できるのであれば、move を追加することは理にかなっています。あなたreally_trivialの動きは、コピーがすでにあるのと同じくらい効率的である可能性があります.

于 2011-01-18T12:50:08.177 に答える