移動セマンティクスは、値を返す際に必ずしもそれほど大きな改善とは限りませshared_ptr
ん。また、おそらく(または類似の)を使用する場合は、早すぎるペシマイズになります。現実には、ほぼすべての合理的に最新のコンパイラーは、Return Value Optimization(RVO)およびNamed Return Value Optimization(NRVO)と呼ばれるものを実行します。つまり、実際に値をコピーするのではなく、値を返すときに、戻り値の後に値が割り当てられる場所への非表示のポインタ/参照を渡すだけで、関数はそれを使用して最終的に値を作成します。C ++標準にはこれを許可する特別な規定が含まれているため、たとえコピーコンストラクターに目に見える副作用があったとしても、値を返すためにコピーコンストラクターを使用する必要はありません。例えば:
#include <vector>
#include <numeric>
#include <iostream>
#include <stdlib.h>
#include <algorithm>
#include <iterator>
class X {
std::vector<int> a;
public:
X() {
std::generate_n(std::back_inserter(a), 32767, ::rand);
}
X(X const &x) {
a = x.a;
std::cout << "Copy ctor invoked\n";
}
int sum() { return std::accumulate(a.begin(), a.end(), 0); }
};
X func() {
return X();
}
int main() {
X x = func();
std::cout << "sum = " << x.sum();
return 0;
};
ここでの基本的な考え方は非常に単純です:可能な場合はコピーを避けたい(コンテンツにstd::vector
32767のランダムな整数を入れて)十分なコンテンツを持つクラスを作成します。明示的なコピーアクターがあり、コピーされた場合/コピーされた場合に表示されます。また、オブジェクト内のランダムな値を使用して何かを行うためのコードがもう少しあります。そのため、オプティマイザーは、クラスが何もしないからといって、クラスに関するすべてを削除しません
次に、関数からこれらのオブジェクトの1つを返すコードを用意し、合計を使用して、オブジェクトが完全に無視されるだけでなく、実際に作成されるようにします。はい、私はかなり確信してしても、高速コピーがあることだ-私たちはそれを実行すると、少なくとも最近の/近代的なコンパイラで、我々は我々が書いたコピーコンストラクタが、すべてで動作しないことを見つけるshared_ptr
何のコピーをやっていないよりもまだ遅いですまったく。
移動すると、それなしでは(直接)できなかったかなりの数のことができます。外部マージソートの「マージ」部分を考えてみましょう。たとえば、一緒にマージする8つのファイルがあるとします。理想的にはあなたにこれらのファイルのすべての8を入れたいのですがvector
-ので、しかしvector
(のように、C ++ 03)は要素をコピーできるようにする必要があり、そしてifstream
sはあなたには、いくつかとしている立ち往生し、コピーすることはできませんunique_ptr
/ shared_ptr
、またはその順序で何かをベクトルに入れることができます。なお、でも私たちの(例えば)の場合reserve
のスペースvector
私たちは必ず私たちのしているので、ifstream
コードはいてもコンパイルされませんので、sが実際にコピーされることはありません、コンパイラはそれを知ることができません我々はコピーコンストラクタはなることはありません知っていますとにかく使用されます。
まだコピーできませんが、C ++ 11では移動ifstream
できます。この場合、オブジェクトはおそらく移動されませんが、必要に応じてコンパイラーを満足させることができるので、スマートポインターハッキングなしでifstream
オブジェクトをvector
直接配置できます。
ベクトルませ拡大は、移動の意味が本当に/かかわらず便利ですできる時間のかなりまともな例です。この場合、関数からの戻り値(または非常に類似したもの)を処理していないため、RVO / NRVOは役に立ちません。オブジェクトを保持するベクターが1つあり、それらのオブジェクトを新しい大きなメモリチャンクに移動する必要があります。
C ++ 03では、新しいメモリにオブジェクトのコピーを作成してから、古いメモリの古いオブジェクトを破壊することでそれを行いました。ただし、古いコピーを破棄するためだけにすべてのコピーを作成するのは、時間の無駄です。C ++ 11では、代わりに移動することが期待できます。これにより、通常、本質的に、(一般的にはるかに遅い)ディープコピーの代わりにシャローコピーを実行できます。言い換えれば、文字列またはベクトルを使用して(ほんの2、3の例のみ)、ポインターが参照するすべてのデータのコピーを作成するのではなく、オブジェクト内のポインターをコピーするだけです。
shared_ptr
高速コピーのためだけに注意してください)、ムーブセマンティクスがコーディング、セマンティクス、クリーンさのペナルティーをほとんど伴わずに同じことを達成できる場合。