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)
Bar() : Foo(this) {}
Run Code Online (Sandbox Code Playgroud)
当你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对此却一无所知; 因为你是单独构建它们的.当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();
}
}
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)
| 归档时间: |
|
| 查看次数: |
966 次 |
| 最近记录: |