【问题标题】:Why can I not push_back a unique_ptr into a vector?为什么我不能将 unique_ptr 推回向量中?
【发布时间】:2011-03-18 01:27:56
【问题描述】:

这个程序有什么问题?

#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

【问题讨论】:

    标签: c++ stl c++11 smart-pointers unique-ptr


    【解决方案1】:

    你需要移动unique_ptr:

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

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

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

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

    在 C++14 中,我们有一个更好的方法:

    make_unique<int>(5);
    

    【讨论】:

    • 既然只能有一个,那么也应该可以将一个临时值直接传递给向量:vec.push_back(std::unique_ptr&lt;int&gt;(new int(1)));unique_ptr 也可以使用自定义删除器(它什么都不做),但必须考虑到局部变量的地址在作用域结束时变得无效。
    • 另一种选择是使用emplace_back。例如vec.emplace_back(new int(1));
    • @deft_code:不,这不安全。 emplace_back 操作可以抛出,如果抛出,动态分配的int 将被泄露。经验法则是所有动态分配都应该由一个命名的智能指针拥有,以避免泄漏。
    • make_shared() 返回一个 shared_ptr,而不是一个 unique_ptr。不幸的是,C++11 中没有 make_unique() ;一个不幸的遗漏,希望在 C++14 中得到修复
    • @FKaria make_unique() 意味着 new 永远不需要直接调用,这改变了程序员的思维方式并避免(显着减少)内存泄漏。像“避免新的和删除的”这样的建议可以出现在迈耶斯/亚历山大雷斯库/萨特的下一版书中:)
    【解决方案2】:

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

    请参阅using unique_ptr with standard library containers 以进一步阅读。

    【讨论】:

    • 参见this comment - 使用智能指针时使用emplace_x() 函数是不安全的。
    • 那么将 unique_ptr 存储到向量中的最佳方法是什么?与我测试的原始指针相比,它非常慢。
    • @user2189731:这很奇怪,std::vectorstd::unique_ptr 都是模板类,应该允许大量的编译器优化。 std::unique_ptr 唯一做的就是防止复制分配,其他一切都应该优化为原始指针访问。
    猜你喜欢
    • 2012-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-09
    • 1970-01-01
    • 2014-02-16
    相关资源
    最近更新 更多