前方声明不会做

时间:2010-10-26 12:49:29

标签: c++ forward-declaration

以下是代码的两个片段(准备编译)。在第一个片段中,我只使用了一个结构的前向声明,同时从一个基类的dtor中删除了指向这个结构的指针,不调用Guest类。
在第二个片段中,当代替前向声明时,我使用基本工作中的删除使用删除的此Guest类的完整定义 为什么?为什么会有所作为?是不是前向声明假设只是编译器的一个注释,说这个类/结构的定义在其他地方?
我很惊讶它只是不直观地工作。

//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;
}

//秒 - 完全def

#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;
}

6 个答案:

答案 0 :(得分:16)

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

  

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

因此,您不能在不完整类型上使用删除。它会调用析构函数,编译器还没有意识到它。

答案 1 :(得分:3)

除非您知道其定义,否则无法删除访客。它的析构函数不会被调用。 此外,如果Guest已定义自定义操作员删除,则会将其忽略。

答案 2 :(得分:3)

您无法删除指向不完整类型的指针。删除是要求类型完成的操作之一。 HTH

答案 3 :(得分:3)

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

形式上,5.3.5 / 5:

  

如果要删除的对象有   不完整的类型   删除和完整的类有一个   非平凡的析构函数或者   解除分配函数,行为是   未定义。

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

答案 4 :(得分:2)

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

答案 5 :(得分: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.

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