执行“删除此”操作时缺少虚拟析构函数

发布于 2024-12-05 09:45:25 字数 1034 浏览 1 评论 0原文

C++ FAQ Lite 的 16.15 部分讨论了 < code>删除此然后提到:

当然,通常的警告适用于 this 指针的情况 当您没有虚拟析构函数时,指向基类的指针。

为什么这是真的?考虑这段代码:

class ISuicidal {
public:
    virtual void suicide() = 0;
};

class MyKlass : public ISuicidal {
public:
    MyKlass() {
        cerr << "MyKlass constructor\n";
    }

    ~MyKlass() {
        cerr << "MyKlass destructor\n";
    }

    void suicide() {
        delete this;
    }
};

这样使用:

int main()
{
    ISuicidal* p = new MyKlass;
    p->suicide();
    return 0;
}

在调用 p->suicide() 中,MyKlass 的析构函数按预期调用,即使 ISuicidal 没有虚拟析构函数

对我来说这是有道理的,因为在 MyKlass::suicide 中,this 的静态类型已知为 MyKlass*,因此正确的析构函数被调用。通过在 suicide 中放置 typeid 调用,可以轻松验证这一点。

那么,是FAQ条目不准确,还是我误解了它?

Section 16.15 of the C++ FAQ Lite discusses delete this and then mentions:

Naturally the usual caveats apply in cases where your this pointer is
a pointer to a base class when you don't have a virtual destructor.

Why is this true? Consider this code:

class ISuicidal {
public:
    virtual void suicide() = 0;
};

class MyKlass : public ISuicidal {
public:
    MyKlass() {
        cerr << "MyKlass constructor\n";
    }

    ~MyKlass() {
        cerr << "MyKlass destructor\n";
    }

    void suicide() {
        delete this;
    }
};

Used thus:

int main()
{
    ISuicidal* p = new MyKlass;
    p->suicide();
    return 0;
}

In the call p->suicide(), the destructor of MyKlass is called as expected, even though ISuicidal has no virtual destructor.

To me this makes sense, because in MyKlass::suicide, the static type of this is known to be MyKlass*, so the correct destructor is invoked. This is easy to verify by placing typeid calls inside suicide.

So is the FAQ entry inaccurate, or am I misunderstanding it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

动次打次papapa 2024-12-12 09:45:25

你误会了。在ISuicidal中实现自杀函数(即delete this),你会发现当this指针是基类时,对其调用delete并不会调用派生类的析构函数。

You are misunderstanding. Implement the suicide function (ie delete this) in ISuicidal and you will find that when the this pointer is a base class calling delete on it doesn't call the derived class's destructor.

痞味浪人 2024-12-12 09:45:25

在你的函数 suicide(),
您正在使用删除此;
这里,this指针对应于类MyKlass,因为该函数是在MyKlass中定义的,而不是在ISuicidal中,因此调用了MyKlass的析构函数。

如果您在 ISuicidal 中定义了该函数,那么它不会调用 MyKlass 的析构函数,除非您在 ISuicidal 中声明虚拟析构函数。

In your function suicide(),
You are using delete this;
Here, the this pointer corresponds to the class MyKlass, as the function is defined in MyKlass and not ISuicidal, and therefore the destructor of MyKlass is called.

If you had defined the function in ISuicidal, then it would not call the destructor of MyKlass unless you declare a virtual destructor in ISuicidal.

情话墙 2024-12-12 09:45:25

如果您在派生自 MyClass 的层次结构中引入另一个实际类(例如 MyClass2),就会出现问题。

class ISuicidal {
public:
    virtual void suicide() = 0;
};

class MyKlass : public ISuicidal {
public:
    MyKlass() {
       cerr << "MyKlass constructor\n";
    }

    ~MyKlass() {
        cerr << "MyKlass destructor\n";
    }

    void suicide() {
        delete this;
    }
};

class MyKlass2 : public MyKlass {
public:
    MyKlass2() {
        cerr << "MyKlass2 ctr"<<std::endl;
    } 

    ~MyKlass2() {
        cerr << "MyKlass2 dtr"<<std::endl;
    }
}

int main()
{
    MyKlass* p = new MyKlass2;
    delete p; //destructor of base class called, not the destructor of MyKlass2 because
              //the destructor is not virtual
    return 0;
}

the problem arises if you introduce another real class in the hierarchy that derives from MyClass (e.g. MyClass2).

class ISuicidal {
public:
    virtual void suicide() = 0;
};

class MyKlass : public ISuicidal {
public:
    MyKlass() {
       cerr << "MyKlass constructor\n";
    }

    ~MyKlass() {
        cerr << "MyKlass destructor\n";
    }

    void suicide() {
        delete this;
    }
};

class MyKlass2 : public MyKlass {
public:
    MyKlass2() {
        cerr << "MyKlass2 ctr"<<std::endl;
    } 

    ~MyKlass2() {
        cerr << "MyKlass2 dtr"<<std::endl;
    }
}

int main()
{
    MyKlass* p = new MyKlass2;
    delete p; //destructor of base class called, not the destructor of MyKlass2 because
              //the destructor is not virtual
    return 0;
}
不一样的天空 2024-12-12 09:45:25

子类:public MyKlass {
〜孩子(){}
};

ISuicidal* p = new Child;

p->suicide(); // ~Child() 未调用!

class Child : public MyKlass {
~Child () {}
};

ISuicidal* p = new Child;

p->suicide(); // ~Child() not called !

蓝礼 2024-12-12 09:45:25

我认为你误解了它。当您在基类中调用 delete this 时,即 this 指针具有指向基类的指针类型时,就会出现此问题。

当然,通常的警告适用于 this 指针的情况
当您没有虚拟析构函数时,指向基类的指针。

在您的示例中,这不是指向基类的指针,而是指向派生类的指针。

I think you're misunderstanding it. The issue occurs when you call delete this in the base class, that is when the this pointer has a type of pointer to the base class.

Naturally the usual caveats apply in cases where your this pointer is
a pointer to a base class when you don't have a virtual destructor.

In your example this is not a pointer to the base class but rather a pointer to the derived class.

说好的呢 2024-12-12 09:45:25

只要您调用实例的确切析构函数(例如,不调用基类的析构函数),它就是安全的。

因此,您可以通过为每个子类正确实现 suicide() 来安全地实现这一点 - 或者通过创建一个可由 this 访问的外部删除器函数(或任何管理这个)。

it's safe as long as you call the exact destructor of the instance (e.g. do not call the destructor of a base).

therefore, you can safely accomplish this by properly implementing suicide() for every subclass - or by creating an external deleter function which is accessible to this (or whatever manages the lifetime of this).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文