2014-05-09 16 views
6

Si consideri il seguente codice C++ 11:Perché questo codice non verrà compilato se viene dichiarato il distruttore?

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

Se una delle linee che dichiarano il distruttore sul codice precedente non sia commentata, questo codice non viene compilato. Il compilatore si lamenta del fatto che il copy construtor di std::thread viene cancellato. Ma std::vector::emplace_back non dovrebbe fare uso del costruttore di copia, quindi, perché fallisce? E perché diavolo importa la menzione del distruttore?

uscita GCC (~A() {}; senza commenti):

$ 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; 
    ^

uscita Clang (~A() {}; senza commenti):

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

La specifica esplicita del distruttore inibisce il costruttore di movimento sintetizzato dal compilatore. Dovrai aggiungerne uno manualmente. – 0x499602D2

+0

Grazie. Aggiungere 'A (A && o) = predefinito;' risolto il mio problema. – lvella

risposta

6

(Risposta tratto da commenti, nessun credito preso da me)

Se un il distruttore è dichiarato manualmente, il costruttore di mosse predefinito non viene creato durante la compilazione. Forzando il costruttore di mosse predefinito da utilizzare verrà risolto questo problema:

A(A&& o) = default; 
+2

Vale la pena ricordare che il codice funzionerebbe se A avesse un membro copiabile invece di std :: thread dato che il costruttore di copie di A non sarebbe cancellato implicitamente in quel caso (preferirei non modificare la risposta dal mio telefono). – jrok

Problemi correlati