简体   繁体   English

来自抽象类的unique_ptr的shared_ptr

[英]shared_ptr from unique_ptr of abstract class

I'm trying to follow Herb Sutter's C++ guidelines, in this case to prefer unique_ptr to raw pointers and shared_ptr . 我试图遵循Herb Sutter的C ++指南,在这种情况下更喜欢unique_ptr到原始指针和shared_ptr One of the arguments in favour of std::unique_ptr is convertibility to shared_ptr should that be needed at some point. 支持std::unique_ptr一个参数是在某些时候需要转换为shared_ptr

In my case I have a vector of unique_ptr that I need to pass to a method that takes a vector of shared_ptr . 在我的例子中,我有一个unique_ptrvector ,我需要传递给一个带有shared_ptr vector的方法。 I was hoping to be able to write something like: 我希望能写出类似的东西:

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

This gives me the following error with my Xcode 7.1 based toolchain configured for C++11 : 这为我为基于Xcode 7.1C++11工具链配置了以下错误:

error: field type 'Abstract' is an abstract class. 错误:字段类型'Abstract'是一个抽象类。

It seems the STL is trying to hold a concrete instance of type Abstract when I use make_shared . 当我使用make_shared时,似乎STL试图保持Abstract类型的具体实例。 That would seem to make Mr. Sutter's advice unworkable in many cases, so I'm sure I must be doing something wrong! 这似乎使Sutter先生的建议在许多情况下变得不可行,所以我确信我一定做错了! I've resorted to writing: 我求助于写作:

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

Is there a better way to do this? 有一个更好的方法吗?

make_shared constructs a new object using the given arguments and returns a shared_ptr to it. make_shared使用给定的参数构造一个新对象,并向其返回一个shared_ptr So the compiler expects a constructor Abstract(std::unique_ptr<Abstract>) , which is probably not what you have. 所以编译器需要一个构造函数Abstract(std::unique_ptr<Abstract>) ,这可能不是你拥有的。

What you want is the constructor of shared_ptr that takes a unique_ptr argument: 你想要的是shared_ptr的构造函数,它接受一个unique_ptr参数:

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

and, as it's not explicit , then 而且,因为它不explicit ,那么

    vectorShared.emplace_back(move(uniquePtr));

will just work (I've used emplace_back to avoid redundant copying, at Richard Hodges's suggestion). 只会工作(我在Richard Hodges的建议中使用了emplace_back来避免冗余复制)。 There's even a standard algorithm, so you don't need the for loop: 甚至还有一个标准算法,所以你不需要for循环:

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

If you need this regularly, you might define a function: 如果您经常需要这个,您可以定义一个函数:

#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));
}

Sorry about the terrible name (I'm open to suggestions). 抱歉这个可怕的名字(我愿意接受建议)。 If you omit the call to reserve() , you could generalise it to more containers. 如果省略对reserve()的调用,则可以将其推广到更多容器。

I would do it like this: 我会这样做:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM