【问题标题】:Error with `std::vector< std::unique_ptr< T > >``std::vector< std::unique_ptr< T > > 出错
【发布时间】:2015-10-11 16:27:53
【问题描述】:

我看到std::vector&lt; std::unique_ptr&lt; T &gt; &gt;std::move 一起传递时出现一些错误。重现问题的代码是这样的:

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

使用 clang 3.4,此代码会产生此错误:

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

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

根据this answer 和 cmets,这不应该在这些编译器上发生,但我没有做完全相同的事情:我正在尝试使用初始化列表初始化向量。

知道需要做什么才能正确构建此代码吗?

【问题讨论】:

标签: c++ c++11 stdvector move-semantics unique-ptr


【解决方案1】:

braced-init-listgetVector内的return语句中的使用

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

导致调用带有initializer_list&lt;T&gt; 参数的std::vector&lt;T&gt; 构造函数。即使您正在移动 unique_ptrinitializer_list only allows const access to its elements,因此 vector 将尝试复制 unique_ptr,从而导致您看到的错误。

您可以通过采用更详细的方式来构造vector 来修复错误

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

Live demo


出于好奇,可以从一组只能移动的对象构造vector,但您需要通过std::move_iterator 来移动元素。

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

【讨论】:

  • @0x499602D2 push_back 返回void...?
  • 我更喜欢v.emplace_back(new bar());v.push_back(std::make_unique&lt;bar&gt;());
  • @RedAlert 我也更喜欢后者,但问题标记为 C++11。并且使用emplace_back(new T()) 不是异常安全的。
【解决方案2】:

你的 vtype 是一个唯一指针向量,你返回一个唯一指针。

由于您在构造函数 foo 中进行移动,因此您不需要返回移动 看看这段代码:

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

【讨论】:

    猜你喜欢
    • 2018-02-02
    • 2019-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多