为什么我不能将unique_ptr push_back到vector中?

285

这个程序有什么问题?

#include <memory>
#include <vector>

int main()
{
    std::vector<std::unique_ptr<int>> vec;

    int x(1);
    std::unique_ptr<int> ptr2x(&x);
    vec.push_back(ptr2x); //This tiny command has a vicious error.

    return 0;
}

错误信息:

In file included from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/mingw32/bits/c++allocator.h:34:0,
                 from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/allocator.h:48,
                 from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/memory:64,
                 from main.cpp:6:
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h: In member function 'void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = std::unique_ptr<int>, _Tp* = std::unique_ptr<int>*]':
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/stl_vector.h:745:6:   instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::unique_ptr<int>, _Alloc = std::allocator<std::unique_ptr<int> >, value_type = std::unique_ptr<int>]'
main.cpp:16:21:   instantiated from here
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h:207:7: error: deleted function 'std::unique_ptr<_Tp, _Tp_Deleter>::unique_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = int, _Tp_Deleter = std::default_delete<int>, std::unique_ptr<_Tp, _Tp_Deleter> = std::unique_ptr<int>]'
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/ext/new_allocator.h:105:9: error: used here
In file included from c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/vector:69:0,
                 from main.cpp:7:
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h: In member function 'void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const std::unique_ptr<int>&}, _Tp = std::unique_ptr<int>, _Alloc = std::allocator<std::unique_ptr<int> >, std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >, typename std::vector<_Tp, _Alloc>::_Base::_Tp_alloc_type::pointer = std::unique_ptr<int>*]':
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/stl_vector.h:749:4:   instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::unique_ptr<int>, _Alloc = std::allocator<std::unique_ptr<int> >, value_type = std::unique_ptr<int>]'
main.cpp:16:21:   instantiated from here
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/unique_ptr.h:207:7: error: deleted function 'std::unique_ptr<_Tp, _Tp_Deleter>::unique_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = int, _Tp_Deleter = std::default_delete<int>, std::unique_ptr<_Tp, _Tp_Deleter> = std::unique_ptr<int>]'
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/bits/vector.tcc:314:4: error: used here
2个回答

420

你需要移动 unique_ptr

vec.push_back(std::move(ptr2x));

unique_ptr保证单个容器拥有被持有的指针所有权。这意味着您不能复制unique_ptr(因为这样两个unique_ptr将具有所有权),所以您只能移动它。

但请注意,您当前使用unique_ptr的方式是不正确的。您不能使用它来管理指向本地变量的指针。本地变量的生命周期是自动管理的:当块结束时(例如,在此情况下函数返回时),本地变量将被销毁。您需要动态分配对象:

std::unique_ptr<int> ptr(new int(1));

在C++14中,我们有一种更好的方法来实现这个:

make_unique<int>(5);

12
既然只能有一个,那么也应该能够直接将临时对象传递给向量:vec.push_back(std::unique_ptr<int>(new int(1)));unique_ptr 也可以使用自定义删除器(什么也不做),但在这种情况下必须注意,局部变量的地址在作用域结束时会变得无效。 - UncleBens
20
另一个选项是使用 emplace_back。例如: vec.emplace_back(new int(1)); - deft_code
88
不,那不太安全。emplace_back 操作可能会抛出异常,如果确实发生异常,动态分配的 int 将无法释放。一般来说,所有动态分配的内存应该由具有名称的智能指针拥有,以避免泄漏。 - James McNellis
8
make_shared() 返回一个 shared_ptr,而不是 unique_ptr。不幸的是,在 C++11 中没有 make_unique(),这是一个不幸的遗漏,希望在 C++14 中能够解决。 - cdmh
31
make_unique()意味着不需要直接调用new,这改变了程序员的思维方式并避免(大幅减少)内存泄漏。像“避免使用new和delete”这样的建议可以出现在Meyers/Alexandrescu/Sutter的下一版书中 :) - cdmh
显示剩余6条评论

34

std::unique_ptr没有拷贝构造函数。您可以创建一个实例,然后在初始化期间请求std :: vector复制该实例。

error: deleted function 'std::unique_ptr<_Tp, _Tp_Deleter>::uniqu
e_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = int, _Tp_D
eleter = std::default_delete<int>, std::unique_ptr<_Tp, _Tp_Deleter> =
 std::unique_ptr<int>]'

该类符合MoveConstructible和MoveAssignable的要求,但不符合CopyConstructible和CopyAssignable的要求。

以下内容适用于新的emplace调用。

std::vector< std::unique_ptr< int > > vec;
vec.emplace_back( new int( 1984 ) );

详见使用 unique_ptr 与标准库容器进行进一步阅读。


7
请看这个评论 - 当使用智能指针时,使用emplace_x()函数是不安全的。请注意不要更改原文意思,并将翻译内容写在此处,不包括解释和其他额外信息。 - Qix - MONICA WAS MISTREATED
2
那么将unique_ptr存储到vector中的最佳方法是什么?根据我的测试,与原始指针相比,它非常慢。 - user2189731
3
这很奇怪,std::vectorstd::unique_ptr 都是模板类,应该允许编译器进行大量优化。std::unique_ptr 唯一阻止的是复制赋值,其他所有操作都应该被优化为原始指针访问。 - vgru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接