2015-07-22 22 views
8

Ich sehe einige Fehler, die std::vector< std::unique_ptr<T> > mit std::move umgehen. Der Code, der das Problem reproduziert, ist dies:Fehler mit `std :: vector <std :: unique_ptr < T >>`

#include <memory> // for std::unique_ptr 
#include <utility> // for std::move 
#include <vector> // for std::vector 

struct bar {}; 
using vtype = std::vector<std::unique_ptr<bar>>; 

struct foo 
{ 
    foo(vtype v) : _v(std::move(v)) { } 
private: 
    vtype _v; 
}; 

vtype getVector() 
{ 
    return { std::move(std::unique_ptr<bar>(new bar())) }; 
};  

int main() 
{ 
foo f(std::move(getVector())); 
}; 

Mit Klirren 3.4, erzeugt dieser Code diesen Fehler:

$ clang++ -std=c++11 test.cpp -o xtest 
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/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 deleted constructor of 
     'std::unique_ptr<bar, std::default_delete<bar> >' 
    { ::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<std::unique_ptr<bar, std::default_delete<bar> >, const std::unique_ptr<bar, std::default_delete<bar> > &>' 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<const std::unique_ptr<bar, std::default_delete<bar> > *, std::unique_ptr<bar, std::default_delete<bar> > *>' 
     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<const std::unique_ptr<bar, std::default_delete<bar> > *, std::unique_ptr<bar, std::default_delete<bar> > *>' 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_vector.h:1204:11: note: in instantiation of function template specialization 
     'std::__uninitialized_copy_a<const std::unique_ptr<bar, std::default_delete<bar> > *, std::unique_ptr<bar, std::default_delete<bar> > *, std::unique_ptr<bar, 
     std::default_delete<bar> > >' requested here 
      std::__uninitialized_copy_a(__first, __last, 
       ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_vector.h:368:2: note: in instantiation of function template specialization 
     'std::vector<std::unique_ptr<bar, std::default_delete<bar> >, std::allocator<std::unique_ptr<bar, std::default_delete<bar> > > >::_M_range_initialize<const 
     std::unique_ptr<bar, std::default_delete<bar> > *>' requested here 
     _M_range_initialize(__l.begin(), __l.end(), 
     ^
test.cpp:17:12: note: in instantiation of member function 'std::vector<std::unique_ptr<bar, std::default_delete<bar> >, std::allocator<std::unique_ptr<bar, 
     std::default_delete<bar> > > >::vector' requested here 
    return { std::move(std::unique_ptr<bar>(new bar())) }; 
     ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/unique_ptr.h:273:7: note: function has been explicitly marked deleted here 
     unique_ptr(const unique_ptr&) = delete; 
    ^
1 error generated. 

Die Situationen scheint nicht besser mit g zu sein ++ 4.8:

$ g++-4.8 -std=c++11 test.cpp -o xtest 
In file included from /usr/include/c++/4.8/memory:64:0, 
       from test.cpp:1: 
/usr/include/c++/4.8/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::unique_ptr<bar>; _Args = {const std::unique_ptr<bar, std::default_delete<bar> >&}]’: 
/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 = const std::unique_ptr<bar>*; _ForwardIterator = std::unique_ptr<bar>*; 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 = const std::unique_ptr<bar>*; _ForwardIterator = std::unique_ptr<bar>*]’ 
/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 = const std::unique_ptr<bar>*; _ForwardIterator = std::unique_ptr<bar>*; _Tp = std::unique_ptr<bar>]’ 
/usr/include/c++/4.8/bits/stl_vector.h:1206:27: required from ‘void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const std::unique_ptr<bar>*; _Tp = std::unique_ptr<bar>; _Alloc = std::allocator<std::unique_ptr<bar> >]’ 
/usr/include/c++/4.8/bits/stl_vector.h:369:36: required from ‘std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = std::unique_ptr<bar>; _Alloc = std::allocator<std::unique_ptr<bar> >; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<std::unique_ptr<bar> >]’ 
test.cpp:17:59: required from here 
/usr/include/c++/4.8/bits/stl_construct.h:75:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = bar; _Dp = std::default_delete<bar>]’ 
    { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); } 
    ^
In file included from /usr/include/c++/4.8/memory:81:0, 
       from test.cpp:1: 
/usr/include/c++/4.8/bits/unique_ptr.h:273:7: error: declared here 
     unique_ptr(const unique_ptr&) = delete; 
    ^

Nach this answer und den Kommentaren, sollte dies nicht auf diese Compiler geschehen, aber ich mache nicht genau das gleiche: Ich versuche, den Vektor mit einer Initialisierungsliste zu initialisieren.

Haben Sie eine Idee, was passieren muss, damit dieser Code korrekt erstellt wird?

+1

kann leicht mit einem nicht-kopierbaren 'bar' http reproduziert werden /coliru.stacked-crooked.com/a/f8344e87a2d4374e – 0x499602D2

Antwort

8

Die von der getVector

return { std::move(std::unique_ptr<bar>(new bar())) }; 

Ergebnisse in einem Aufruf der std::vector<T> Konstruktor innerhalb verspannt-init-Liste in der return-Anweisung verwendet, die ein initializer_list<T> Argument. Auch wenn Sie die unique_ptr sich bewegen, ein initializer_listonly allows const access to its elements, aufgrund derer die vector versucht, die unique_ptr, was zu dem Fehler, den Sie sehen, zu kopieren.

Sie den Fehler, indem man auf eine ausführlichere Art und Weise des Aufbaus der vector

vtype getVector() 
{ 
    vtype v; 
    v.push_back(std::unique_ptr<bar>(new bar())); 
    return v; 
} 

Live demo


Für Neugier willen beheben kann, ist es möglich, eine vector aus einem Array von konstruieren Nur-Verschieben-Objekte, aber Sie müssen std::move_iterator durchlaufen, um die Elemente zu verschieben.

vtype getVector() 
{ 
    std::unique_ptr<bar> arr[] = {std::unique_ptr<bar>(new bar())}; 
    return {std::make_move_iterator(std::begin(arr)), 
      std::make_move_iterator(std::end(arr))}; 
} 
+2

@ 0x499602D2 'push_back' gibt 'void' ... zurück? –

+0

@ T.C. Du hast recht :) – 0x499602D2

+0

ich lieber 'v.emplace_back (neue Bar());' oder 'v.push_back (std :: make_unique ());' –

-1

Ihre vtype ist ein Vektor von einzigartigen Zeiger und Sie ihm einen einzigartigen Zeiger zurück.

, da Sie den Umzug in den Konstruktor foo tun Sie nicht brauchen eine Bewegung werfen Sie einen Blick auf diesen Code zurück: /:

#include <memory> // for std::unique_ptr 
#include <utility> // for std::move 
#include <vector> // for std::vector 

struct bar {}; 
using vtype = /*std::vector<*/std::unique_ptr<bar>/*>*/; 

struct foo 
{ 
    foo(vtype v) : _v(std::move(v)) { } 
private: 
    vtype _v; 
}; 

vtype getVector() 
{ 
    return /*{ std::move(*/ std::unique_ptr<bar>(new bar()) /*) }*/; 
};  

int main() 
{ 
foo f(std::move(getVector())); 
};