来自抽象类的unique_ptr的shared_ptr

时间:2015-12-08 18:21:52

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

我试图遵循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的工具链提供了以下错误:

  

错误:字段类型&#39;摘要&#39;是一个抽象的类。

当我使用make_shared时,似乎STL正试图保留for (auto &uniquePtr : vectorUnique) { auto ptr = uniquePtr.get(); auto shared = shared_ptr<Abstract>(ptr); vectorShared.push_back(shared); uniquePtr.release(); } 类型的具体实例。这似乎会使Sutter先生的建议在许多情况下变得不可行,所以我确定我一定做错了!我已经采取了写作:

#ifndef TEST_H
#define TEST_H


class test
{
 public:
    test();
 };

#endif // TEST_H

有更好的方法吗?

2 个答案:

答案 0 :(得分:7)

make_shared使用给定的参数构造一个新对象,并向其返回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来避免冗余复制,在Richard Hodges的建议中)。甚至还有标准算法,因此您不需要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()的调用,则可以将其推广到更多容器。

答案 1 :(得分:2)

我会这样做:

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