为继承enable_shared_from_this的类获取unique_ptr [英] Getting a unique_ptr for a class that inherits enable_shared_from_this

查看:116
本文介绍了为继承enable_shared_from_this的类获取unique_ptr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常,我更喜欢从工厂返回 unique_ptr
最近,我遇到了一个问题,即为继承 enable_shared_from_this 的类返回 unique_ptr 。此类的用户可能会意外地调用 shared_from_this(),尽管该调用不属于任何 shared_ptr ,结果带有 std :: bad_weak_ptr 异常(或直到C ++ 17之前未定义的行为,通常作为异常来实现)。

Usually I prefer returning unique_ptr from Factories. Recently I came to the problem of returning a unique_ptr for a class that inherits enable_shared_from_this. Users of this class may accidentally cause a call to shared_from_this(), though it is not owned by any shared_ptr, which results with a std::bad_weak_ptr exception (or undefined behavior until C++17, which is usually implemented as an exception).

代码的简单版本:

class Foo: public enable_shared_from_this<Foo> {
    string name;
    Foo(const string& _name) : name(_name) {}
public:
    static unique_ptr<Foo> create(const string& name) {
        return std::unique_ptr<Foo>(new Foo(name));
    }
    shared_ptr<Foo> get_shared() {return shared_from_this();}
    void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
    virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};

int main() {
    // ok behavior
    auto pb1 = Foo::create("pb1");
    pb1->doIt();
    shared_ptr<Foo> pb2 = shared_ptr<Foo>(std::move(pb1));
    shared_ptr<Foo> pb3 = pb2->get_shared();
    pb3->doIt();

    // bad behavior
    auto pb4 = Foo::create("pb4");
    pb4->doIt();
    shared_ptr<Foo> pb5 = pb4->get_shared(); // exception
    pb5->doIt();    
}

可能的解决方案是更改工厂方法以返回 shared_ptr ,但这不是我想要的,因为在许多情况下,实际上不需要共享,这会使事情效率降低。

A possible solution is to change the factory method to return shared_ptr but this is not what I'm looking for, as in many cases there is actually no need for sharing and this will make things less efficient.

问题是如何实现以下所有条件:

The question is how to achieve all of the following:


  1. 允许工厂返回 unique_ptr

  2. 允许该类的 unique_ptr 成为共享对象

  3. allow shared_ptr 此类的共享副本(通过 shared_from_this()

  4. 避免当此类的 unique_ptr 试图从此共享时失败(在上面的示例中调用 get_shared

  1. allow the factory to return unique_ptr
  2. allow unique_ptr of this class to become shared
  3. allow shared_ptr of this class to get shared copies (via shared_from_this())
  4. avoid failure when unique_ptr of this class tries to get shared from this (calling get_shared in above example)

上面的代码满足了项目1至3,问题出在项目4

Items 1 to 3 are fulfilled with the code above, the problem is with item 4.

推荐答案

使用多个静态工厂函数和转换函数。为了解决您的意见,我添加了 get_shared 以支持复制共享指针。可以在此处编译: http://ideone.com/UqIi3k

Use multiple static factory functions and conversion functions. To address your comments, I've added get_shared to support copying a shared pointer. This compiles and is available here: http://ideone.com/UqIi3k

#include <iostream>
#include <memory>

class Foo
{
    std::string name;
    Foo(const std::string& _name) : name(_name) {}
public:
    void doIt() const { std::cout << "Foo::doIt() <" << name << '>' << std::endl;}
    virtual ~Foo() { std::cout << "~Foo() <" << name << '>' << std::endl;}

    static std::unique_ptr<Foo> create_unique(const std::string & _name) {
        return std::unique_ptr<Foo>(new Foo(_name));
    }
    static std::shared_ptr<Foo> create_shared(const std::string & _name) { 
        return std::shared_ptr<Foo>(new Foo(_name));
    }

    static std::shared_ptr<Foo> to_shared(std::unique_ptr<Foo> &&ptr ) { 
         return std::shared_ptr<Foo>(std::move(ptr)); 
    }
    static std::shared_ptr<Foo> get_shared(const std::shared_ptr<Foo> &ptr) {
         return std::shared_ptr<Foo>(std::move(ptr));
    }
};

int main() {
    // ok behavior
    auto pb1 = Foo::create_unique("pb1");
    pb1->doIt();
    std::shared_ptr<Foo> pb2 = Foo::get_shared(std::move(pb1));
    //note the change below
    std::shared_ptr<Foo> pb3 = Foo::get_shared(pb2);
    pb3->doIt();

    // also OK behavior
    auto pb4 = Foo::create_unique("pb4");
    pb4->doIt();
    std::shared_ptr<Foo> pb5 = Foo::to_shared(std::move(pb4)); // no exception now
    pb5->doIt();

    std::shared_ptr<Foo> pb6 = Foo::create_shared("pb6");
    pb6->doIt();
    std::shared_ptr<Foo> pb7 = std::shared_ptr<Foo>(pb5);
    pb7->doIt();
    return 0;
}

这篇关于为继承enable_shared_from_this的类获取unique_ptr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆