6

下面是两个代码片段(准备编译)。在第一个片段中,我只对结构使用前向声明,同时从 Guest 类的基类 dtor 中删除指向该结构的指针,但没有调用。
在第二个片段中,我使用了这个 Guest 类的完整定义,而不是前向声明,使用 Base 中的 delete 来达到预期的效果。
为什么?为什么会有所作为?前向声明不应该只是编译器说明这个类/结构的定义在其他地方的注释吗?
我很惊讶它不能直观地工作。

//First just forward dclr  
#include "stdafx.h"
#include <iostream>
using std::cout;

struct Guest;

struct Base
{
    Guest* ptr_;
    Base(Guest* ptr):ptr_(ptr)
    {
        cout << "Base\n";
    }
    ~Base()
    {
        cout << "~Base\n";
        delete ptr_;
    }
};

struct Guest
{
    Guest()
    {
        cout << "Guest\n";
        throw std::exception();
    }
    Guest(int)
    {
        cout << "Guest(int)\n";
    }
    ~Guest()
    {
        cout << "~Guest\n";
    }
};

struct MyClass : Base
{
    Guest g;
    MyClass(Guest* g):Base(g)
    {
        cout << "MyClass\n";

    }
    ~MyClass()
    {
        cout << "~MyClass\n";
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        Guest* g = new Guest(1);
    MyClass mc(g);
    }
    catch(const std::exception& e)
    {
        std::cerr << e.what();
    }
    return 0;
}

//第二 - 全高清

#include "stdafx.h"
#include <iostream>
using std::cout;

struct Guest
{
    Guest()
    {
        cout << "Guest\n";
        throw std::exception();
    }
    Guest(int)
    {
        cout << "Guest(int)\n";
    }
    ~Guest()
    {
        cout << "~Guest\n";
    }
};

struct Base
{
    Guest* ptr_;
    Base(Guest* ptr):ptr_(ptr)
    {
        cout << "Base\n";
    }
    ~Base()
    {
        cout << "~Base\n";
        delete ptr_;
    }
};



struct MyClass : Base
{
    Guest g;
    MyClass(Guest* g):Base(g)
    {
        cout << "MyClass\n";

    }
    ~MyClass()
    {
        cout << "~MyClass\n";
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        Guest* g = new Guest(1);
    MyClass mc(g);
    }
    catch(const std::exception& e)
    {
        std::cerr << e.what();
    }
    return 0;
}
4

6 回答 6

16

来自 C++ 标准(5.3.5/5):

如果要删除的对象在删除点具有不完整的类类型,并且完整的类具有非平凡的析构函数或释放函数,则行为未定义。

因此,您不能在不完整的类型上使用 delete。它会调用析构函数,编译器还不知道它。

于 2010-10-26T12:55:02.963 回答
3

除非您知道其定义,否则您无法删除来宾。它的析构函数不会被调用。此外,如果 Guest 定义了自定义运算符 delete,它将被忽略。

于 2010-10-26T12:55:01.240 回答
3

您不能删除指向不完整类型的指针。删除是需要类型完整的操作之一。高温高压

于 2010-10-26T12:55:24.767 回答
3

非正式地:编译器需要类定义才能正确删除对象,因为它需要知道如何调用析构函数和/或operator delete该类。

正式地,5.3.5/5:

如果要删除的对象在删除点具有不完整的类类型,并且完整的类具有非平凡的析构函数或释放函数,则行为未定义。

如果(例如)Guest是 POD,你会没事的,但是你给了它一个析构函数,所以你不行。

于 2010-10-26T12:59:23.847 回答
2

ptr_调用时的类型不完整delete。这会导致未定义的行为。所以你的析构函数可能不会被调用。您可以使用Boost.checked_delete来避免这种情况。

于 2010-10-26T12:57:08.507 回答
2

(stdafx.h 头文件不是标准的 c++。)如果我用 g++ 编译,编译器会生成:

 warning: possible problem detected in invocation of delete operator:
 warning: invalid use of incomplete type ‘struct Guest’
 warning: forward declaration of ‘struct Guest’
 note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.

配置您的编译器以在适当的警告和错误级别进行编译。

于 2010-10-26T12:57:36.750 回答