2015-07-22 21 views
8

Tôi nhìn thấy một số lỗi khi đi qua std::vector< std::unique_ptr<T> > xung quanh với std::move. Mã mà tái tạo vấn đề là thế này:Lỗi với `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())); 
}; 

Với vang 3.4, mã này tạo ra lỗi này:

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

các tình huống dường như không được bất kỳ tốt hơn với g ++ 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; 
    ^

Theo this answer và các nhận xét, điều này không nên xảy ra trên các trình biên dịch này, nhưng tôi không thực hiện chính xác như cũ: Tôi đang cố gắng khởi tạo vectơ bằng danh sách khởi tạo.

Bất kỳ ý tưởng nào cần phải xảy ra để mã này có thể xây dựng chính xác?

+1

có thể được sao chép một cách dễ dàng với một tổ chức phi copyable 'bar' http://coliru.stacked-crooked.com/a/f8344e87a2d4374e – 0x499602D2

Trả lời

8

Các sử dụng của chuẩn bị tinh thần-init-list trong câu lệnh return trong getVector

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

kết quả trong một cuộc gọi đến constructor std::vector<T> rằng có một đối initializer_list<T>. Mặc dù bạn đang di chuyển unique_ptr, một initializer_listonly allows const access to its elements, do đó vector sẽ cố gắng sao chép unique_ptr, dẫn đến lỗi bạn thấy.

Bạn có thể sửa lỗi bằng cách phải dùng đến một cách tiết hơn về xây dựng vector

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

Live demo


Vì tò mò, nó có thể để xây dựng một vector từ một loạt các các đối tượng chỉ di chuyển, nhưng bạn cần phải đi qua std::move_iterator để di chuyển các phần tử.

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' trả về' void' ...? –

+0

@ T.C. Bạn đúng :) – 0x499602D2

+0

Tôi thích 'v.emplace_back (thanh mới());' hoặc 'v.push_back (std :: make_unique ());' –

-1

vtype của bạn là một vectơ con trỏ độc đáo và bạn quay lại con trỏ duy nhất.

kể từ khi bạn đang làm di chuyển trong foo constructor bạn không cần phải trả lại một động thái hãy xem để mã này:

#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())); 
}; 
Các vấn đề liên quan