Consider the following C++11 code:
#include <thread>
#include <vector>
struct A {
A() {}
//virtual ~A() = default;
//~A() = default;
//~A() {};
std::thread t;
};
int main()
{
std::vector<A> v;
v.emplace_back();
}
If any of the lines declaring the destructor on the previous code is uncommented, this code won't compile. The compiler complains about copy construtor of std::thread
being deleted. But std::vector::emplace_back
should make no use of copy constructor, so, why it fails? And why the heck the mention of the destructor matters?
GCC output (~A() {};
uncommented):
$ g++ --std=c++11 -o test test.cpp
In file included from /usr/include/c++/4.8/memory:64:0,
from /usr/include/c++/4.8/thread:40,
from test.cpp:1:
/usr/include/c++/4.8/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = A; _Args = {A}]’:
/usr/include/c++/4.8/bits/stl_uninitialized.h:75:53: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<A*>; _ForwardIterator = A*; bool _TrivialValueTypes = false]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:117:41: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<A*>; _ForwardIterator = A*]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:258:63: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<A*>; _ForwardIterator = A*; _Tp = A]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:281:69: required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = A*; _ForwardIterator = A*; _Allocator = std::allocator<A>]’
/usr/include/c++/4.8/bits/vector.tcc:415:43: required from ‘void std::vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&& ...) [with _Args = {}; _Tp = A; _Alloc = std::allocator<A>]’
/usr/include/c++/4.8/bits/vector.tcc:101:54: required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = A; _Alloc = std::allocator<A>]’
test.cpp:17:17: required from here
/usr/include/c++/4.8/bits/stl_construct.h:75:7: error: use of deleted function ‘A::A(const A&)’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
test.cpp:4:8: note: ‘A::A(const A&)’ is implicitly deleted because the default definition would be ill-formed:
struct A {
^
test.cpp:4:8: error: use of deleted function ‘std::thread::thread(const std::thread&)’
In file included from test.cpp:1:0:
/usr/include/c++/4.8/thread:126:5: error: declared here
thread(const thread&) = delete;
^
Clang output (~A() {};
uncommented):
$ clang++ --std=c++11 -o test test.cpp
In file included from test.cpp:1:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:40:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/memory:64:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_construct.h:75:38: error:
call to implicitly-deleted copy constructor of 'A'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_uninitialized.h:75:8: note:
in instantiation of function template specialization
'std::_Construct<A, A>' requested here
std::_Construct(std::__addressof(*__cur), *__first);
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_uninitialized.h:117:2: note:
in instantiation of function template specialization
'std::__uninitialized_copy<false>::__uninit_copy<std::move_iterator<A *>,
A *>' requested here
__uninit_copy(__first, __last, __result);
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_uninitialized.h:258:19: note:
in instantiation of function template specialization
'std::uninitialized_copy<std::move_iterator<A *>, A *>' requested here
{ return std::uninitialized_copy(__first, __last, __result); }
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_uninitialized.h:279:19: note:
in instantiation of function template specialization
'std::__uninitialized_copy_a<std::move_iterator<A *>, A *, A>' requested
here
return std::__uninitialized_copy_a
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/vector.tcc:413:15: note:
in instantiation of function template specialization
'std::__uninitialized_move_if_noexcept_a<A *, A *, std::allocator<A> >'
requested here
= std::__uninitialized_move_if_noexcept_a
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/vector.tcc:101:4: note:
in instantiation of function template specialization 'std::vector<A,
std::allocator<A> >::_M_emplace_back_aux<>' requested here
_M_emplace_back_aux(std::forward<_Args>(__args)...);
^
test.cpp:17:4: note: in instantiation of function template specialization
'std::vector<A, std::allocator<A> >::emplace_back<>' requested here
v.emplace_back();
^
test.cpp:11:14: note: copy constructor of 'A' is implicitly deleted because
field 't' has a deleted copy constructor
std::thread t;
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:126:5: note:
'thread' has been explicitly marked deleted here
thread(const thread&) = delete;
^
1 error generated.
(Answer taken from comments, no credit taken by me)
If a destructor is declared manually, the default move constructor is not created when compiling. Forcing the default move constructor to be used will fix this:
A(A&& o) = default;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With