【问题标题】:std::list< std::unique_ptr<T> >: passing it aroundstd::list< std::unique_ptr<T> >:传递它
【发布时间】:2010-07-11 11:44:40
【问题描述】:

假设我有一个std::listclass T

std::list<T> l;

将它传递给函数时,我会使用引用:

someFunction( std::list<T> &l )

传递std::listunique_ptrs 的(元素)的最佳方式是什么?

std::list< std::unique_ptr<T> >  l;

像这样:

someFunction( std::unique_ptr<T> ptr )

或者这个:

someFunction( T* ptr )

或者这个:

someFunction( T &ref )

例如,我如何使用std::listback() 函数来调用它?恕我直言,这些都是“某种”等价物,但我确定我在这里遗漏了一些东西。

谢谢

【问题讨论】:

    标签: c++ c++11 unique-ptr


    【解决方案1】:

    按照从好到坏的顺序:

    1. someFunction(const T&);
    2. someFunction(T&);
    3. someFunction(const std::unique_ptr&);
    4. someFunction(std::unique_ptr&);

    第一个是最好的,因为它不会修改它的对象,并且无论您如何分配它,它都会与该对象一起工作(例如,您可以毫无问题地切换到 shared_ptr)。

    无论您使用什么智能指针,第二个也可以使用;但是,它假定您可以修改对象,并且只要您可以将某些东西设为 const,就应该这样做。

    数字 3 和 4 都允许被指向的对象发生变异;然而,#3 不允许修改智能指针,而数字 4 允许。两者都有强制使用 unique_ptr 的缺点,而上面的两个无论智能指针类如何都可以工作。

    不能像在其他一些示例中那样按值传递 unique_ptr; unique_ptr 应该是唯一的。如果要复制它,请考虑使用 shared_ptr。

    对于前两个,如果你在 back() 的结果上调用它,它看起来像:

    someFunction(*(lst.back()));  // dereference lst.back() before passing it in.
    

    对于后两者,如果你在 back() 的结果上调用它,它看起来像:

    someFunction(lst.back()); // pass the smart pointer, not the object to
                              // which the smart pointer currently points.
    

    【讨论】:

    • 感谢您的深入解释。因此,智能指针不需要特殊的语义(解除引用除外)。我知道const 的东西,但在这种情况下,我需要修改传入的T 对象。
    【解决方案2】:

    不要按值传递unique_ptr,首先,如果没有std::move,它将无法编译,如果您这样做使用std::move,它将为空您存储在 list 中的值,您将无法再访问它。

    这是因为unique_ptr 不可复制,它没有unique_ptr::unique_ptr(const unique_ptr&lt;T&gt;&amp; other) 类型的复制构造函数,而是只有一个移动构造函数(unique_ptr::unique_ptr(unique_ptr&lt;T&gt;&amp;&amp; source))。

    【讨论】:

    • 我从相反的要求来到这里:我如何从列表中弹出一个unique_ptr,因为当前的 API 需要复制 (auto res = list.back(); list.pop_back(); return res;),所以你回答了我的问题:std::move back 指针中的值,然后将空指针弹出。
    【解决方案3】:

    unique_ptr 以及包含 unique_ptr 的类/实例可以在 std::list (和其他容器)中使用,前提是它们具有 move 构造函数 class_name(class_name &amp;&amp;) 定义(其中 unique_ptr 当然有)。

    当你传递这些元素时,你总是在移动(而不是复制)它们,所以你总是在左值上使用 std::move() ,就像在
    my_list.push_back(std::move(my_element));
    这表明您正在将元素传递(= 移动)到列表中,并且 my_element 在该操作之后是“空的”(如空的 unique_ptr)。

    例子:

    typedef std::unique_ptr<uint8_t[]> data_ptr;
    
    class data_holder
    {
    private:
        int something_about_data;
        data_ptr data;
    public:
        data_holder(data_ptr && _data)
            : data(std::move(_data))
        {}
    
        // hey compiler, please generate a default move constructor for me
        // despite of present destructor
        data_holder(data_holder &&) = default;
    
        ~data_holder()
        {
            // ...
        }
    
        bool is_empty() const { return ! bool(data); }
    }
    
    // ...
    {
        // ...
        data_holder the_element(data_ptr(new uint8_t[DATA_SIZE]));
    
        // move the_element into the_list
        the_list.push_back(std::move(the_element));
        if (the_element.is_empty())
            std::cerr << "data_holder 'the_element' is now empty!" << std::endl;
        // ...
    }
    

    【讨论】:

      猜你喜欢
      • 2019-11-07
      • 2015-07-23
      • 2018-02-02
      • 2020-04-17
      • 2015-10-11
      • 2012-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多