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

use*_*352 192 c++ stl smart-pointers unique-ptr c++11

这个程序有什么问题?

#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;
}
Run Code Online (Sandbox Code Playgroud)

错误:

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
Run Code Online (Sandbox Code Playgroud)

Jam*_*lis 298

你需要移动unique_ptr:

vec.push_back(std::move(ptr2x));
Run Code Online (Sandbox Code Playgroud)

unique_ptr保证单个unique_ptr容器拥有所保持指针的所有权.这意味着您无法复制a unique_ptr(因为那时两个unique_ptrs将拥有所有权),因此您只能移动它.

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

std::unique_ptr<int> ptr(new int(1));
Run Code Online (Sandbox Code Playgroud)

  • @deft_code:不,那不安全.`emplace_back`操作可以抛出,如果是,则动态分配的`int`将被泄露.经验法则是所有动态分配都应该由命名的智能指针拥有,以避免泄漏. (71认同)
  • @FKaria make_unique()意味着`new`永远不需要直接调用,这会改变程序员的思维模式并避免(显着减少)内存泄漏.像"避免新的和删除"这样的建议可以出现在下一版的Meyers/Alexandrescu/Sutter的书中:) (28认同)
  • 另一种选择是使用`emplace_back`.例如`vec.emplace_back(new int(1));` (17认同)
  • 因为只能有一个,所以也应该能够将临时直接传递给向量:`vec.push_back(std :: unique_ptr <int>(new int(1)));`.`unique_ptr`也可以使用自定义删除器(什么都不做),但是必须考虑到局部变量的地址在范围的末尾变得无效. (12认同)
  • make_shared()返回一个shared_ptr,而不是unique_ptr.不幸的是,C++ 11中没有make_unique(); 一个令人遗憾的遗漏,希望将在C++ 14中修复 (8认同)

Ben*_*rst 21

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>]'
Run Code Online (Sandbox Code Playgroud)

该类满足MoveConstructible和MoveAssignable的要求,但不满足CopyConstructible或CopyAssignable的要求.

以下适用于新的emplace调用.

std::vector< std::unique_ptr< int > > vec;
vec.emplace_back( new int( 1984 ) );
Run Code Online (Sandbox Code Playgroud)

请参阅将unique_ptr与标准库容器一起使用以进一步阅读.

  • 参见[this comment](/sf/ask/229864491/#comment11813799_3283795) - 使用`emplace_x() `使用智能指针时,函数是不安全的. (3认同)
  • 那么将 unique_ptr 存储到向量中的最佳方法是什么?正如我测试的那样,与原始指针相比,它非常慢。 (2认同)
  • @user2189731:这很奇怪,“std::vector”和“std::unique_ptr”都是模板化类,应该允许大量编译器优化。`std::unique_ptr` 唯一做的就是防止复制分配,其他所有内容都应该针对原始指针访问进行优化。 (2认同)