【问题标题】:How to declare a vector of unique_ptr's as class data member?如何将 unique_ptr 的向量声明为类数据成员?
【发布时间】:2012-01-24 14:15:21
【问题描述】:

我想要一个 unique_ptr 的向量作为我正在创建的类的成员。

class Foo {
    [...]

private:
    vector<unique_ptr<Bar>> barList;
}

但随后我开始从 VS2010 编译器收到神秘的错误消息:

error C2248: 'std::unique_ptr<_Ty>::operator =' : cannot access private member declared in class 'std::unique_ptr<_Ty>'

以及下面的一些错误行,这些错误行深入到 Microsoft 的 std::_Copy_impl&lt;&gt; 实现中......

我将成员声明更改为

vector<unique_ptr<Bar>>* barList;

然后编译。但是我不禁想知道为什么我不能按照我最初想要的方式去做呢?为了咧嘴笑,我试过了,效果很好:

vector<Bar> barList;

但现在我失去了unique_ptr 的便利。我想要我的蛋糕,我也想吃!

【问题讨论】:

  • 我在看stackoverflow.com/questions/8553464/vector-as-a-class-member,答案似乎认为像我一样声明vector 就可以了。但是,由于某种原因,添加unique_ptr 部分时似乎会触发非法复制。
  • 你的拷贝构造函数和赋值运算符是什么样的?
  • 私有赋值,但复制构造函数是罪魁祸首。当我意识到我使用了错误的所有权语义时,从unique_ptr 切换到shared_ptr

标签: c++ visual-studio-2010 vector unique-ptr


【解决方案1】:

这里的问题是,您的代码在某处试图调用Foo 的“复制分配”运算符。

这会导致编译器尝试生成一个复制赋值运算符,该运算符调用Foo 的所有子对象的复制赋值运算符。最终,这会导致尝试复制 unique_ptr,这是不可能的操作。

【讨论】:

  • 感谢您指出这一点。编译器误导了我,因为错误引用了成员声明并且没有提到导致复制的违规代码。我想这是 VS2010 中的一个缺陷,并有望随着新版本的改进而改进。我的Foo 类有一个复制构造函数,我试图将向量从源Foo 复制出来。共享所有权似乎是更好的解决方案,因此切换到 shared_ptr 就行了。
  • 它看起来像 VS2010 中的一个错误,即使我的代码从未尝试调用复制分配,我也会收到此错误。禁用 operator= 并声明为私有(因此 =delete 不受支持)可以解决问题。
【解决方案2】:

unique_ptr 没有复制语义,因此您不能使用任何方法来复制包含的对象。您可以通过在尝试复制的地方使用std::move 来使用右值引用来执行此操作。如果没有看到您的代码,我无法说出那会在哪里。

如果它以第二种形式编译,要么您没有使用相同的代码,要么存在编译器错误。两者都应该以同样的方式失败。

您的第三个示例,按值存储是最简单的方法,除非您的对象很大且按值存储/复制的成本很高。

【讨论】:

  • auto_ptr 是不遵守正常复制语义的,unique_ptr 根本没有具有复制语义
  • 你和 Mankarse 的答案非常相似。然而,他让我意识到我需要继续寻找有问题的代码(你的回答更巧妙地解决了这个问题)。不过,你们俩都应该得到公认的答案。感谢您的帮助!
【解决方案3】:

std::move(iUniquePtr) 通常在某处丢失(例如,在使用 push_back 时)。

【讨论】:

    【解决方案4】:

    摘自 www.cplusplus.com

    std::unique_ptr::operator=
    

    unique_ptr 赋值 对象获得 x 内容的所有权,包括存储的指针和存储的删除器(以及在某个时刻删除对象的责任)。在调用之前由 unique_ptr 对象拥有的任何对象都被删除(就像调用了 unique_ptr 的析构函数一样)。

    但也有警告:

    本页描述了最新版本的 C++ 标准 (2011) 引入的功能。旧的编译器可能不支持它。

    MSVC 2010 将 operator= 定义为私有(不可复制),但支持 swap 方法。

    【讨论】:

      【解决方案5】:

      常见的问题是erase()emplace*()push*()。这些将尝试移动矢量元素,因为其中一个或多个被删除或插入。虽然这应该可行,因为std::unique_ptr 是可移动的,并且并不严格要求移位,但有时它不会,原因是STL 实现中的错误。出于这个原因,使用std::list 可能会更好,使用std::shared_ptrs,使用std::vector 替代方案,提交错误,或者只使用原始指针,这是一个非常简单有效的解决方案。

      【讨论】:

        【解决方案6】:

        您不能在向量中使用 unique_ptr,因为向量实现强烈依赖于值分配运算符,该运算符在 unique_ptr 中是私有的。使用 boost 中的 shared_ptr 或 C++11 中的其他智能 ptr 实现。

        【讨论】:

        • C++11 容器需要与 unique_ptr 等仅移动类型一起使用。
        • 我的意思是他使用它的方式。但是,谢谢你,我不知道 emplace_back。
        • 你不需要使用emplace_back。只要你给它r值,你就可以使用push_back。
        猜你喜欢
        • 2017-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-22
        相关资源
        最近更新 更多