【问题标题】:Cannot understand how to add new object to std::list<std::unique_ptr<classname>>无法理解如何将新对象添加到 std::list<std::unique_ptr<classname>>
【发布时间】:2014-11-23 12:20:05
【问题描述】:

我对 std::list of unique_ptr's 有一个奇怪的问题。

slFlyingMonster 类派生自 slMonster 类。

以下代码有效:

std::unique_ptr<slMonster> ptr(new slFlyingMonster(md));

但是这段代码:

std::list<std::unique_ptr<slMonster>> mMonsters;
mMonsters.push_back(new slFlyingMonster(md));

抛出错误:

"错误 1 ​​错误 C2664: 'void
std::list>,std::allocator>>>::push_back(const std::unique_ptr<_ty>> &)':无法转换 来自 'slFlyingMonster *' 的参数 1 到 'std::unique_ptr> &&'"

虽然我理解,有些地方是错误的,例如 std::list.push_back() 与 = 不同,但我无法弄清楚如何正确地将新类作为 unique_ptr 添加到列表中。任何建议都会非常受欢迎。

【问题讨论】:

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


    【解决方案1】:

    当您拥有列表所包含类型的对象并且想要推送其副本时,请使用push_back。通常,如果你还没有这样的对象(在你的情况下,你没有),你最好直接在列表中初始化一个新对象——改用emplace_back

    std::list<std::unique_ptr<slMonster>> mMonsters;
    mMonsters.emplace_back(new slFlyingMonster(md));
    

    但是,正如@SebastianRedl 在 cmets 中正确指出的那样,上述内容存在异常安全的问题。如果std::list 内部新节点的内部分配抛出,新的slFlyingMonster 实例将被泄露。当参数之一是未受保护的资源(例如拥有内存的原始指针)时,emplace_back 不是正确的选择。

    所以你实际上想要构造一个包装智能指针并将其推入列表中。在 C++14 中,您可以使用 std::make_unique

    std::list<std::unique_ptr<slMonster>> mMonsters;
    mMonsters.push_back(std::make_unique<slFlyingMonster>(md));
    

    使用纯 C++11,您可以实现自己的 make_unique,或显式创建智能指针:

    std::list<std::unique_ptr<slMonster>> mMonsters;
    mMonsters.emplace_back(std::unique_ptr<slMonster>(new slFlyingMonster(md)));
    

    【讨论】:

    • mMonsters.push_back( { new slFlyingMonster(md) } ); 不会编译。该构造函数是explicit
    • @T.C.非常感谢,已修复。我的印象是列表初始化允许显式构造函数。我的立场是正确的
    • 这不是异常安全的。 list 必须先分配一个新节点才能构造元素,这可能会抛出,在这种情况下,新分配的对象会泄漏。
    • @SebastianRedl 谢谢,已解决
    • 太棒了。对于那些坚持使用 C++11 的人来说,这是一个 make_unique 实现:herbsutter.com/gotw/_102
    【解决方案2】:

    您可以使用emplace_back:

    std::list<std::unique_ptr<slMonster>> mMonsters;
    mMonsters.emplace_back(new slFlyingMonster(md));
    

    或 push_back 一个std::make_unique:

    std::list<std::unique_ptr<slMonster>> mMonsters;
    mMonsters.push_back(std::make_unique<slFlyingMonster>(md));
    

    std::movestd::unique_ptr

    std::list<std::unique_ptr<slMonster>> mMonsters;
    std::unique_ptr<slMonster> p(new slFlyingMonster(md));
    mMonsters.push_back(std::move(p));
    

    构造函数std::unique_ptr&lt;T&gt;(T*)explicit,所以T* 不能隐式构造std::unique_ptr

    【讨论】:

    • 如果你也解释一下emplace_back(T&amp;&amp;...)push_back(T&amp;&amp;)的区别就更好了。
    • push_back(make_unique...) 是最好的解决方案。第一个不是异常安全的。第三个过于冗长,除非您在创建对象和添加对象之间做更多的事情。
    【解决方案3】:

    使用mMonsters.emplace_back,以便从参数中给出的参数创建对象。

    【讨论】:

      猜你喜欢
      • 2023-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-16
      • 2012-12-11
      • 2015-11-08
      • 2014-01-11
      相关资源
      最近更新 更多