Bug 52745 - GCC4.7 vector uses copy instead of move constructor
GCCに上がってたバグレポ。
GCC 4.6.1から4.7にしたら、ムーブコンストラクタがあるのにコピーコンストラクタが呼ばれるようになったそうです。プログラムは以下:
#include <iostream> #include <vector> struct Stuff { Stuff() {} Stuff(Stuff&&) { std::cout << "Move" << std::endl; } Stuff(const Stuff&) { std::cout << "Copy" << std::endl; } }; int main() { std::vector<Stuff> stuff; std::cout << "1" << std::endl; stuff.push_back(Stuff()); std::cout << "2" << std::endl; stuff.push_back(Stuff()); std::cout << "3" << std::endl; stuff.push_back(Stuff()); }
GCC 4.6.1の結果:
1 Move 2 Move Move 3 Move Move Move
GCC 4.7の結果:
1 Move 2 Move Copy 3 Move Copy Copy
GCC 4.7でstd::vectorの実装に修正が入り、push_backの内部ではstd::move_if_noexcept()を使用するようになったため、noexceptじゃないムーブコンストラクタが呼ばれなくなったそうです。
コンパイラによって暗黙定義されるムーブコンストラクタはnoexceptですが、自分で定義したときにnoexceptを付けていないのが原因ですね。
以下のように、ムーブコンストラクタにnoexceptを付ければ、GCC 4.6.1と同様、コピーコンストラクタが呼ばれず全てムーブになります:
#include <iostream> #include <vector> struct Stuff { Stuff() {} Stuff(Stuff&&) noexcept { std::cout << "Move" << std::endl; } Stuff(const Stuff&) { std::cout << "Copy" << std::endl; } }; int main() { std::vector<Stuff> stuff; std::cout << "1" << std::endl; stuff.push_back(Stuff()); std::cout << "2" << std::endl; stuff.push_back(Stuff()); std::cout << "3" << std::endl; stuff.push_back(Stuff()); }
1 Move 2 Move Move 3 Move Move Move