나는 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
은 rvalue 참조를 허용 할 수 있으므로이 경우이 값을 사용하며 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++입니다.
유니온의 std :: string은 (예 : –
) 희망합니다.이 union의 임의의 인스턴스 (지정되지 않은 소스에서 온 것)가 생성 된'std :: string'을 포함하는지 여부를 어떻게 결정합니까? 움직일 수있는, 또는 다른 원시 타입 중 하나? 주어진 유니온이 실제로'bool' 값을 포함하고 있다면'std :: string'에 포함 된 것으로 추정되는 것들을 이동 시키려고하면 무한한 우스꽝스러운 결과가 발생합니다. 생각해 보면 잠시 동안 자신의 질문에 대답 할 수 있어야합니다. –