继承和智能指针(std :: shared_ptr)

Hen*_*nri 1 c++ inheritance virtual-functions smart-pointers shared-ptr

有很多事情需要说.首先,我想知道下面的方法是否被认为是设计模式甚至是一种常用技术(这就是为什么我没有提供有关标题的更多信息).如果是这样,那么名字是什么?无论如何,这是我想要实现的缩小版本.由于我需要使用复制,我发现使用std :: shared_ptr是最好避免被释放(删除)的指针.

class Foo
{
public:
    Foo() : ptr(nullptr) {}
    Foo(const Foo& foo) : ptr(foo.ptr) {}
    virtual ~Foo() = default;

    void whatever() {
        if (ptr)
            ptr->whateverHandler();
    }

    void reset() {
        ptr.reset();
    }

    void resetBar() {
        ptr.reset(new Bar);
    }

    // Other resets here...

protected:
    Foo(Foo* foo) : ptr(foo) {}

private:
    // Every child class should override this
    virtual void whateverHandler() {
        throw "whateverHandler cant be called within base class";
    }

protected:
    std::shared_ptr<Foo> ptr;
};

class Bar : public Foo
{
public:
    Bar() : Foo(this) {}
    void whateverHandler() {
        printf("Bar's handler!!! \n");
    }
};
Run Code Online (Sandbox Code Playgroud)

这一切看起来都很好并编译得很好,但是,下面的exame崩溃了.这是为什么?

int main()
{
    {
        Foo f;

        f.resetBar();
    }

    return getchar();
}
Run Code Online (Sandbox Code Playgroud)

son*_*yao 6

Bar() : Foo(this) {}
Run Code Online (Sandbox Code Playgroud)

当你this转到一个时要小心shared_ptr.

想想以后会发生什么f.resetBar();,并ptr.reset(new Bar);再次.

  1. 因为new Bar,Bar将构造一个类型的对象,并在其构造函数内部this传递给父类成员ptr,然后该对象由它来管理std::shared_ptr.

  2. 之后,对象由f.ptr; 这是另一个std::shared_ptr.

所以有两个人std::shared_ptr指向同一个对象,但是std::shared_ptr对此却一无所知; 因为你是单独构建它们的.当ff.ptr被破坏时,指向的对象也将被破坏.然后该成员ptr将被销毁,它将再次尝试销毁同一个对象,从而导致UB.

我不确定设计试图完成什么,但只是停止传递this到一个std::shared_ptr可以消除UB.

class Foo
{
public:
    virtual ~Foo() = default;
    void whatever() {
        if (ptr)
            ptr->whateverHandler();
    }
    void reset() {
        ptr.reset();
    }
    void resetBar() {
        ptr.reset(new Bar);
    }
    // Other resets here...
private:
    // Every child class should override this
    virtual void whateverHandler() = 0;
    std::shared_ptr<Foo> ptr;
};

class Bar : public Foo
{
public:
    void whateverHandler() {
        printf("Bar's handler!!! \n");
    }
};

int main()
{
    {
        Foo f;
        f.resetBar();
        f.whatever();
        f.resetSthElse();
        f.whatever();
    }
}
Run Code Online (Sandbox Code Playgroud)

而IMO,有一个类型的成员std::shared_ptr指向派生类是令人困惑的; 将它分开可能会更好.然后,我认为这可能是桥梁设计的一部分.

class Foo
{
public:
    void whatever() {
        if (ptr)
            ptr->whateverHandler();
    }
    void reset() {
        ptr.reset();
    }
    void resetBar() {
        ptr.reset(new BarHandler);
    }
    // Other resets here...
private:
    std::shared_ptr<FooHandler> ptr;
};

class FooHandler
{
public:
    virtual ~FooHandler() = default;
    // Every child class should override this
    virtual void whateverHandler() = 0;
};

class BarHandler : public FooHandler
{
public:
    void whateverHandler() {
        printf("Bar's handler!!! \n");
    }
};

int main()
{
    {
        Foo f;
        f.resetBar();
        f.whatever();
        f.resetSthElse();
        f.whatever();
    }
}
Run Code Online (Sandbox Code Playgroud)