我注意到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;
^
我瞭解一些關於什麼可以移動和什麼不能移動的規則,但是這似乎並不重要。爲什麼會發生這種情況,如何解決這個問題,所以它不會調用複製構造函數?
目標編譯器是Clang C++ 14。
我希望'聯盟中的std :: string'只是例如 –
你打算如何確定這個聯盟的某個任意實例(來自某個未指定的源)是否包含構造的'std :: string',可以移動的,還是其他原始類型之一?如果給定的聯合實際上包含'bool'值,試圖移動它所包含的'std :: string'會導致無盡的歡樂。如果你考慮一下,你應該能夠回答你自己的問題。 –