继承和智能指针(std::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");
}
};

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

int main()
{
{
Foo f;
f.resetBar();
}
return getchar();
}
Bar() : Foo(this) {}

this传递给shared_ptr时要小心。

再次思考f.resetBar();ptr.reset(new Bar);之后会发生什么。

  1. 对于new Bar,将构造类型为Bar的对象,并且在其构造函数内this被传递给父类成员ptr,然后该对象由作为std::shared_ptr的it管理。

  2. 之后,对象由f.ptr进行管理;它是另一个CCD_ 11。

所以有两个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();
}
}

而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();
}
}

Foo::ptr保存一个指向其母Foo(this)的指针,引用计数为1。

Foo::resetBar()中,当Foo请求Foo::ptr调用reset(new Bar)时,Foo::ptr将其所有权交给了其母亲Fa(this),并发现引用计数已降至0,因此需要杀死

Foo当Foo死了,它的孩子也会被杀。所以Foo::ptr也必须是死的。然后将CCD_ 26分配给死CCD_。

相关内容

  • 没有找到相关文章

最新更新