前向声明是行不通的
下面是两个代码片段(准备编译)。在第一个片段中,我仅对结构使用前向声明,同时从 Guest 类的基类 dtor 中删除指向该结构的指针,但未调用该结构。
在第二个片段中,我没有使用前向声明,而是使用 Base 工作中的删除来使用此 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;
}
//第二个 - 完整定义
#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;
}
Below are two fragments (ready to compile) of code. In first fragment in which I'm using only forward declaration for a struct while deleting pointer to this struct from a Base class dtor for a Guest class isn't invoked.
In the second fragment when instead of forward declaration I use full definition of this Guest class using delete in Base works ase intended.
Why? Why does it make a difference? Isn't forward declaration suppose to be just a note for a compiler saying that the definition of this class/struct is somewhere else?
I'm very surprised that it just doesn't work intuitively.
//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;
}
//Second - full 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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
来自 C++ 标准 (5.3.5/5):
所以你不能对不完整的类型使用删除。它会调用析构函数,而编译器尚不知道它。
From the C++ standard (5.3.5/5):
So you cannot use delete on your incomplete type. It would call the destructor and the compiler is not yet aware of it.
非正式地:编译器需要类定义才能正确删除对象,因为它需要知道如何调用该类的析构函数和/或删除运算符。
正式来说,5.3.5/5:
如果(例如)
Guest
是 POD,那么你就可以了,但是你给了它一个析构函数,所以你就不行了。Informally: the compiler needs the class definition in order to delete the object correctly, because it needs to know how to call the destructor and/or
operator delete
for that class.Formally, 5.3.5/5:
You'd be OK if (for example)
Guest
was POD, but you gave it a destructor, so you're not OK.您无法删除指向不完整类型的指针。删除是要求类型完整的操作之一。华泰
You cannot delete a pointer to an incomplete type. Delete is one of the operations which requires the type to be complete. HTH
除非您知道来宾的定义,否则您无法删除它。它的析构函数不会被调用。
此外,如果 Guest 定义了自定义运算符删除,它将被忽略。
You can't delete the Guest unless you know its definition. It's destructor won't be called.
Also, if Guest has defined a custom operator delete, it would be ignored.
当您调用
delete
时,ptr_
的类型不完整。这会导致未定义的行为。所以你的析构函数可能不会被调用。您可以使用 Boost.checked_delete 来避免此类情况。The type of
ptr_
is incomplete when you invokedelete
on it. This leads to undefined behavior. So your destructor may not be called. You can use Boost.checked_delete to avoid such scenarios.(stdafx.h 标头不是标准 C++。)
如果我使用 g++ 进行编译,编译器会生成:
配置编译器以在适当的警告和错误级别进行编译。
(The stdafx.h header is not standard c++.)
If I compile with g++, the compiler generates:
Configure your compiler to compile at proper warning and error levels.