如果声明了析构函数,为什么这个代码不会编译?

时间:2014-05-09 23:21:00

标签: c++ c++11

考虑以下C ++ 11代码:

#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();
}

如果取消注释前面代码中声明析构函数的任何行,则此代码不会编译。编译器抱怨正在删除std::thread的复制构造。但std::vector::emplace_back应该不使用复制构造函数,那么,它为什么会失败?为什么提到析构函数很重要?

GCC输出(~A() {};取消注释):

$ 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输出(~A() {};取消注释):

$ 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.

1 个答案:

答案 0 :(得分:6)

(来自评论的回答,我没有信用)

如果手动声明析构函数,则在编译时不会创建默认的移动构造函数。强制使用默认移动构造函数将解决此问题:

A(A&& o) = default;