3

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

vector在我的情况下,我有一个unique_ptr我需要传递给一个需要一个vector的方法shared_ptr。我希望能够写出类似的东西:

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

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

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

Abstract我使用make_shared. 这似乎使萨特先生的建议在很多情况下都行不通,所以我确定我一定做错了什么!我求助于写作:

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

有一个更好的方法吗?

4

2 回答 2

8

make_shared使用给定的参数构造一个新对象并将 a 返回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));

将正常工作(根据理查德霍奇斯的建议,我曾经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(),则可以将其推广到更多容器。

于 2015-12-08T18:28:50.757 回答
2

我会这样做:

for (auto &uniquePtr : vectorUnique) {
    vectorShared.emplace_back(std::move(uniquePtr));
}
于 2015-12-08T18:31:20.787 回答