以下是代码的两个片段(准备编译)。在第一个片段中,我只使用了一个结构的前向声明,同时从一个基类的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;
}
答案 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.
将编译器配置为以适当的警告和错误级别进行编译。