【问题标题】:shared_ptr from unique_ptr of abstract classshared_ptr 来自抽象类的 unique_ptr
【发布时间】:2015-12-08 18:21:52
【问题描述】:

我正在尝试遵循 Herb Sutter 的 C++ 指南,在这种情况下,我更喜欢 unique_ptr 而不是原始指针和 shared_ptr。支持std::unique_ptr 的论据之一是在某些时候需要转换为shared_ptr

就我而言,我有一个 vectorunique_ptr,我需要将其传递给一个采用 vectorshared_ptr 的方法。我希望能够写出类似的东西:

for (auto &uniquePtr : vectorUnique)
    vectorShared.push_back(make_shared<Abstract>(move(uniquePtr));

这给了我为C++11 配置的基于Xcode 7.1 的工具链出现以下错误:

错误:字段类型“抽象”是一个抽象类。

当我使用make_shared 时,STL 似乎试图保存Abstract 类型的具体实例。这似乎使萨特先生的建议在很多情况下都行不通,所以我确定我一定做错了什么!我求助于写作:

for (auto &uniquePtr : vectorUnique) {
    auto ptr = uniquePtr.get();
    auto shared = shared_ptr<Abstract>(ptr);
    vectorShared.push_back(shared);
    uniquePtr.release();
}

有没有更好的方法来做到这一点?

【问题讨论】:

  • 你想要shared_ptr&lt;Abstract&gt;,而不是make_shared&lt;Abstract&gt;。那个构造函数也不是显式的,所以你可以写push_back(std::move(uniquePtr))

标签: c++ c++11 abstract unique-ptr make-shared


【解决方案1】:

make_shared 使用给定的参数构造一个新对象并返回一个shared_ptr 给它。所以编译器需要一个构造函数Abstract(std::unique_ptr&lt;Abstract&gt;),这可能不是你所拥有的。

你想要的是 shared_ptr 的构造函数,它接受一个 unique_ptr 参数:

    vectorShared.push_back(shared_ptr<Abstract>(move(uniquePtr)));

而且,因为不是explicit,所以

    vectorShared.emplace_back(move(uniquePtr));

会正常工作(根据 Richard Hodges 的建议,我使用 emplace_back 来避免重复复制)。甚至还有一个标准算法,所以你不需要for 循环:

    std::move(vectorUnique.begin(), vectorUnique.end(),
              std::back_inserter(vectorShared));

如果你经常需要这个,你可以定义一个函数:

#include <vector>
#include <memory>
#include <algorithm>

template<typename T>
std::vector<std::shared_ptr<T>>
        convert_to_shared(std::vector<std::unique_ptr<T>>&& vu)
{
    using std::begin;
    using std::end;
    std::vector<std::shared_ptr<T>> vs;
    vs.reserve(vu.size());
    std::move(begin(vu), end(vu), std::back_inserter(vs));
    return vs;
}


// Example of use
class Abstract {};
int main()
{
    std::vector<std::unique_ptr<Abstract>> vectorUnique;
    std::vector<std::shared_ptr<Abstract>> vectorShared
        = convert_to_shared(std::move(vectorUnique));
}

对不起这个可怕的名字(我愿意接受建议)。如果省略对reserve() 的调用,则可以将其推广到更多容器。

【讨论】:

  • vectorShared.emplace_back(move(uniquePtr)) - 避免冗余转换。
  • 很高兴你能提到我。如果构造函数是显式的,我也认为 emplace_back 会起作用。很好的答案。
  • 想一想,没有任何优势 - push_back 被重载以接受右值,在这种情况下应该等同于 emplace_back
  • 不完全。 push_back 还有一个多余的动作——即使是复制省略。
【解决方案2】:

我会这样做:

for (auto &uniquePtr : vectorUnique) {
    vectorShared.emplace_back(std::move(uniquePtr));
}

【讨论】:

  • 如果向量的重新分配抛出,这会泄漏。
  • shared_ptr 可以从 r 值崇敬构造为 unique_ptr。无需释放 - 只需移动即可。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-23
  • 2016-04-12
  • 2019-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-12
相关资源
最近更新 更多