shared_ptr 来自 unique_ptr 的摘要 class

shared_ptr from unique_ptr of abstract class

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

在我的例子中,我有一个 unique_ptrvector,我需要将其传递给一个采用 shared_ptrvector 的方法。我希望能够写出类似的东西:

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

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

error: field type 'Abstract' is an abstract class.

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

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

有更好的方法吗?

make_shared 使用给定的参数和 returns 一个 shared_ptr 构造一个新对象。所以编译器需要一个构造函数 Abstract(std::unique_ptr<Abstract>),这可能不是你所拥有的。

你想要的是 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() 的调用,则可以将其推广到更多容器。

我会这样做:

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