move
は、ではなく、のオブジェクトに適用することができますが、 "些細ではない"(正確にはわかりませんが、プリミティブ型は問題ありません)メンバを持つユニオンを持っています。たとえば、次のコードは(C++ 14、Clang)をコンパイルします。"移動"されたオブジェクトが "重大でない"メンバを共用体に持つとき、コピーコンストラクタが強制されるのはなぜですか?
#include <vector>
#include <string>
class Foo {
public:
union {
int i;
bool b;
};
Foo() {};
~Foo() {};
// Move constructor to default.
Foo(Foo &&) = default;
// Copy constructor deleted.
Foo(const Foo &) = delete;
};
int main() {
std::vector<Foo> v;
v.push_back(Foo());
}
コピーコンストラクタが削除されていることに注意してください。 std::vector
のpush_back
は値の参照を受け入れることができるので、この場合はそれを使用し、copy
は発生しません。しかし、「非自明な」型がコピーコンストラクタが強制される組合に追加されたら - それがコンパイルされません。
#include <vector>
#include <string>
class Foo {
public:
union {
int i;
bool b;
std::string s; // <-- Added element causing compile error.
};
Foo() {};
~Foo() {};
// Move constructor to default.
Foo(Foo &&) = default;
// Copy constructor deleted.
Foo(const Foo &) = delete;
};
int main() {
std::vector<Foo> v;
v.push_back(Foo());
}
コンパイラエラーメッセージの関連部分:
In file included from experiment/miniso.cpp:1:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/vector:61:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/allocator.h:46:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/x86_64-linux-gnu/c++/7.2.0/bits/c++allocator.h:33:
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/ext/new_allocator.h:136:23: error: call to deleted constructor of 'Foo'
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/alloc_traits.h:475:8: note: in instantiation of function template
specialization '__gnu_cxx::new_allocator<Foo>::construct<Foo, Foo>' requested here
{ __a.construct(__p, std::forward<_Args>(__args)...); }
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/vector.tcc:100:21: note: in instantiation of function template
specialization 'std::allocator_traits<std::allocator<Foo> >::construct<Foo, Foo>' requested here
_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/stl_vector.h:954:9: note: in instantiation of function template
specialization 'std::vector<Foo, std::allocator<Foo> >::emplace_back<Foo>' requested here
{ emplace_back(std::move(__x)); }
^
experiment/miniso.cpp:24:5: note: in instantiation of member function 'std::vector<Foo, std::allocator<Foo> >::push_back' requested here
v.push_back(Foo());
^
experiment/miniso.cpp:19:3: note: 'Foo' has been explicitly marked deleted here
Foo(const Foo &) = delete;
^
I何が動くことができ、何ができないかに関するいくつかのルールについて知っていますが、これは扱いが簡単ではないようです。なぜこれが起こっているのですか?これを解決してコピーコンストラクタを呼び出さないようにするにはどうすればいいですか?
ターゲットコンパイラはClang C++ 14です。
ユニオンの 'std :: string'がちょうど例えば –
であることを希望します。このユニオンの任意のインスタンス(不特定のソースから来たもの)に構築された' std :: string'が含まれているかどうかを、移動することができる、または他のプリミティブ型の1つですか?与えられた共用体が実際に 'bool'値を含んでいれば、' std :: string'に含まれていると思われるものを移動しようとすると無限の喜びが生じます。あなたがそれについて考えるなら、しばらくの間、自分の質問に答えることができるはずです。 –