通常,我更喜欢从工厂返回unique_ptr
最近,我遇到了为继承unique_ptr的类返回enable_shared_from_this的问题。此类的用户可能会意外地导致对shared_from_this()的调用,尽管该调用不属于任何shared_ptr,但它会导致std::bad_weak_ptr异常(或直到C++ 17时仍未定义的行为,通常是作为异常来实现)。

代码的简单版本:

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,但这不是我想要的,因为在许多情况下,实际上不需要共享,这会使事情效率降低。

问题是如何实现以下所有目标:
  • 允许工厂返回unique_ptr
  • 允许此类的unique_ptr成为共享的
  • 允许此类的shared_ptr获取共享拷贝(通过shared_from_this())
  • 避免此类的unique_ptr尝试与之共享时失败(在上面的示例中调用get_shared)

  • 上面的代码完成了项目1至3,问题在于项目4

    最佳答案

    使用多个静态工厂函数和转换函数。为了解决您的意见,我添加了get_shared以支持复制共享指针。可以在此处编译: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;
    }
    

    10-06 00:58