有很多事情需要说。首先,我想知道下面的方法是否被认为是设计模式甚至是一种常用技术(这就是为什么我没有提供有关标题的更多信息)。如果是这样,那么名字是什么? 无论如何,这是我想要实现的缩小版本。由于我需要使用复制,我发现使用std :: shared_ptr是最好避免被释放(删除)的指针。
value
这一切看起来都很好并且编译得很好,但是,下面的exame崩溃了。那是为什么?
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");
}
};
答案 0 :(得分:6)
Bar() : Foo(this) {}
将this
传递给shared_ptr
时要小心。
考虑一下f.resetBar();
和ptr.reset(new Bar);
之后会发生什么。
对于new Bar
,将构造类型为Bar
的对象,并将其构造函数this
内部传递给父类成员ptr
,然后对象由std::shared_ptr
进行管理。
之后,该对象由f.ptr
管理;这是另一个std::shared_ptr
。
所以有两个std::shared_ptr
指向同一个对象,但是std::shared_ptr
s对此没有任何了解;因为你是单独构建它们的。当f
和f.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
类型的成员指向派生类是令人困惑的;将它分开可能会更好。然后,我认为它可能是bridge design partern。
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();
}
}
答案 1 :(得分:0)
Foo::ptr
拥有指向其母Foo(this)
的指针,其引用次数为1.
在Foo::resetBar()
,当 Foo 要求 Foo :: ptr 致电reset(new Bar)
时, Foo :: ptr 放弃了对其母亲 Foo (this)
的所有权,并发现引用计数已降至0,因此需要杀死 Foo 。
当Foo
死亡时,其子女被杀。所以 Foo :: ptr 也必须死了。然后将new Bar
分配给死Foo::ptr
会导致UB。