malloc() 和虚函数有什么问题?
可能的重复:
C++:为什么需要new
?
为什么我不能使用当我的对象是包含虚函数的类的子对象时,malloc 为它们分配空间?这真是令人沮丧。有充分的理由吗?
下面的程序说明了这个问题。它在第 27 行出现段错误,我在其中调用 aa->f()
#include <iostream>
#include <cstdlib>
class A
{
public:
virtual int f() {return 1;}
};
class B
{
public:
int f() {return 1;}
};
class Aa : public A {};
class Bb : public B {};
int main()
{
Aa* aa = (Aa*)malloc(sizeof(Aa));
Aa* aan = (Aa*)new Aa();
Bb* bb = (Bb*)malloc(sizeof(Bb));
std::cout << bb->f() << std::endl;
std::cout << aan->f() << std::endl;
std::cout << aa->f() << std::endl;
return 0;
}
版本信息:g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5
Possible Duplicate:
C++: why isnew
needed?
Why cant I use malloc to allocate space for my objects when they are children of a class containing virtual functions? This is really frustrating. Is there a good reason?
The following program illustrates the problem. It segfaults on line 27, where I call aa->f()
#include <iostream>
#include <cstdlib>
class A
{
public:
virtual int f() {return 1;}
};
class B
{
public:
int f() {return 1;}
};
class Aa : public A {};
class Bb : public B {};
int main()
{
Aa* aa = (Aa*)malloc(sizeof(Aa));
Aa* aan = (Aa*)new Aa();
Bb* bb = (Bb*)malloc(sizeof(Bb));
std::cout << bb->f() << std::endl;
std::cout << aan->f() << std::endl;
std::cout << aa->f() << std::endl;
return 0;
}
Version info: g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
实现虚函数的常见方法是在距对象负偏移处设置一个指向“虚拟表”或 vtable 的指针。需要这张表来确定要调用哪个虚拟函数。这就是为什么仅仅分配空间不起作用。
A common way to implement virtual functions is to have a pointer to a "virtual table" or vtable at a negative offset from the object. This table is needed to figure out what virtual function to call. This is why just malloc'ing space doesn't work.
malloc
只分配内存,但不创建对象。因此,该行分配了一个足够大的内存区域来容纳
A
,但包含垃圾。正如其他人指出的那样,这也意味着指向 vtable 的指针将不会被设置(我从@David Rodríguez 对另一个答案的评论中得到了这个指针),这是分派对虚拟函数的调用所必需的。由于B
不包含虚函数,因此不会出现这样的问题。但是,如果B
包含任何需要初始化的数据成员,B
也会发生这种情况,如下所示:该行
无需强制转换即可完成:
malloc
only allocates memory, but does not create an object. So, the lineallocates a region of memory that is large enough to hold an
A
, but contains garbage. As others pointed out, this also means that the pointer to thevtable
will not be set (I got that one from @David Rodríguez's comment on another answer), which is required to dispatch calls to virtual functions. SinceB
does not contain virtual functions, no such problem arises. It would happen withB
too, however, ifB
contained any data-members that require initialization, such as this:The line
can do without the cast:
原因是
malloc
对 C++ 构造函数一无所知,因此不会调用它们。您可以使用 placementnew
:请注意,在释放此类内存之前,您必须手动调用析构函数。
The reason is that
malloc
knows nothing about C++ constuctors and consequently does not call them. You can call the constuctors yourself using placementnew
:Note that you have to manually call the destructors before freeing such memory.
不要使用 malloc,使用 new - malloc 不调用构造函数。
当您执行
A * a = new A();
时,编译器将分配内存,为 A 设置 vtable 指针并调用构造函数。当您调用虚函数时,虚函数表用于实际查找该函数。当您执行
A * a = (A *) malloc(...);
时,编译器将分配内存,其中将包含随机数据。当您调用虚拟函数时,它会查看(垃圾)虚函数表并调用一些随机位置。具有虚函数的类在内部看起来像这样:
调用虚函数会查看“隐藏”虚函数表指针,该指针指向类虚函数表,即指向函数的指针的链接列表。所以这个vtable指针必须被初始化,而malloc不会这么做。
Don't use malloc, use new - malloc does not call constructors.
When you do
A * a = new A();
the compiler will allocate memory, set up the vtable pointer for A and call the constructor. When you call a virtual function, the vtable is used to actually find the function.When you do
A * a = (A *) malloc(...);
the compiler will allocate memory, which will contain random data. When you call a virtual function, it'll look at the (garbage) vtable and call some random location.A class with virtual functions look something like this internally:
Calling a virtual function looks at the "hidden" vtable pointer, which points to the class vtable, a linked list of pointers to functions. So this vtable pointer must be initialized, and malloc doesn't do that.
肯定是因为虚拟功能表没有正确创建?
Surely because the Virtual Function Table isn't getting created properly?
malloc 不会调用类的构造函数,因此您的对象未正确初始化,因此会出现段错误。使用 C++ 时,使用
new
分配内存。顺便说一句,不需要转换从new
返回的指针。malloc
does not call the constructor of the class, so your object is not initailized properly, hence it seg faults. Usenew
to allocate memory when using C++. BTW, there is no need to cast the pointer returned fromnew
.很好的理由称为虚拟表。具有虚拟方法的类型的对象有一个指针表,指向要调用的实际虚拟方法的地址。这些称为虚拟表或 v 表。
The good reason is called virtual tables. Objects of types that have virtual methods have a table of pointers pointing to the address of the actual virtual methods to be called. These are called virtual tables or v-tables.