insert
、push_back
およびemplace
(_back
)は、の再割り当てを引き起こす可能性がありstd::vector
ます。次のコードは、コンテナの再割り当て中に要素を移動するのではなく、要素をコピーするのを見て困惑しました。
#include <iostream>
#include <vector>
struct foo {
int value;
explicit foo(int value) : value(value) {
std::cout << "foo(" << value << ")\n";
}
foo(foo const& other) noexcept : value(other.value) {
std::cout << "foo(foo(" << value << "))\n";
}
foo(foo&& other) noexcept : value(std::move(other.value)) {
other.value = -1;
std::cout << "foo(move(foo(" << value << "))\n";
}
~foo() {
if (value != -1)
std::cout << "~foo(" << value << ")\n";
}
};
int main() {
std::vector<foo> foos;
foos.emplace_back(1);
foos.emplace_back(2);
}
特定のコンパイラ(GCC 4.7)を使用している特定のマシンでは、次のように出力されます。
foo(1)
foo(2)
foo(foo(1))
~foo(1)
~foo(1)
~foo(2)
ただし、コピーコンストラクター(foo(foo const&) = delete;
)を削除すると、次の(予期される)出力が生成されます。
foo(1)
foo(2)
foo(move(foo(1))
~foo(1)
~foo(2)
何故ですか?一般的に、移動はコピーよりも効率的であるか、少なくともそれほど効率的ではないでしょうか。
GCC 4.5.1が期待どおりの動作をすることは注目に値します。これは、GCC 4.7でのリグレッションなのか、それとも、コンパイラが私のオブジェクトのコピーが安価であると認識しているため、巧妙な最適化なのか(しかし、どうやって?!)?
また、挿入の前に実験的にを配置することにより、これが再割り当てによって引き起こされていることを確認したことにも注意してください。foos.reserve(2);
これにより、コピーも移動も実行されません。