【问题标题】:unique_ptr that contains unique_ptr包含 unique_ptr 的 unique_ptr
【发布时间】:2021-08-05 10:25:38
【问题描述】:

免责声明:我起初写了一个我认为很清楚的问题版本,但那根本不是。我在这里把它改成了 MRE。

我有以下代码:

#include <map>
#include <memory>
#include <string>

using std::make_unique;
using std::string;
using std::unique_ptr;

template <typename T>
class Holder {
   public:
    Holder() {}
    ~Holder() {}
   private:
    T value_;  // In real life, we can do something with this.
};

struct Thing {
    Thing() {}
};
class ThingCollection {
   public:
    ThingCollection() {}

   private:
    // In real life, I have more maps of <string, Thing*>.
    // Which is why I use a unique_ptr in the map.
    std::map<string, unique_ptr<Thing>> the_map_;
};

我的问题是将unique_ptr 转换为Holder&lt;ThingCollection&gt;,由于缺少复制构造函数而失败。

void foo() {
    Holder<ThingCollection> cm;  // OK.
    auto cmp1 = make_unique<Holder<int>>(Holder<int>());  // OK.
    auto cmp2 = make_unique<ThingCollection>(ThingCollection());    // OK.
    auto cmp3 = make_unique<Holder<int>>(Holder<int>()); // OK.
    auto cmp4 = make_unique<Holder<ThingCollection>>(Holder<ThingCollection>()); // BAD.

}

在编译时,由于复制构造函数(unique_ptr)被隐式删除,最后 (BAD) 行失败。我明白为什么unique_ptr 不可复制,但我不明白它为什么要复制到这里或正确的响应是什么。

我是这样编译的:

clang++ -std=c++14 -pthread -Wall -Wextra -c -o mre.o mre.cc

【问题讨论】:

  • “这当然会导致关于隐式删除的复制构造函数的错误” - 只是因为您可能已经实现了一个成员函数,该函数禁止从生成的移动操作。你有用户定义的LotsOfStuffThing 析构函数吗?如果默认移动操作适合您,请定义 LotsOfStuff(LotsOfStuff&amp;&amp;) = default;
  • 事实上我必须接受你的“当然”并猜测“可能”的原因(因为它不是真的“当然”)有点表明你需要一个合适的 minimal reproducible example 而不是手-挥动代码描述。
  • 我在您的 Thing 课程中没有看到 unique_ptr(好吧,您实际上并没有向我们展示您的 Thing 课程),只有在您的 ThingCollection 课程中。跨度>
  • 创建Thing 对象的管理器并使用工厂创建它们会有所帮助吗?接下来使用shared_ptr 访问Thins 对象?
  • 很明显,unique_ptr 无法管理本身包含 unique_ptr 的东西,至少不能以任何幼稚的方式进行 为什么不呢? unique_ptr 将调用它拥有的对象的析构函数,而后者又调用它包含的任何 unique_ptr 的析构函数

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


【解决方案1】:

当然,这会导致有关隐式删除的复制构造函数的错误。我想我明白为什么会这样了

当您尝试复制具有不可复制成员的类型的对象时,通常会遇到此类错误。

解决方案:不要尝试复制不可复制的对象。


免责声明:显然,unique_ptr 无法管理本身包含 unique_ptr 的东西,至少不能以任何幼稚的方式。

相反,唯一指针可以轻松管理本身包含唯一指针的东西。我能想到的幼稚方法会失败的唯一情况是指针形成递归链 - 本质上是一个链表 - 在这种情况下,您需要一个自定义析构函数来避免线性递归深度。

附:我建议不要使用 ThingCollection 类,而是使用 boost::multi_index_container

【讨论】:

  • 谢谢。现在阅读了boost::multi_index_container 文档,这似乎是最好的策略:它应该解决我遇到的问题并提供更好的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-30
  • 1970-01-01
  • 1970-01-01
  • 2014-12-06
相关资源
最近更新 更多