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()
#incl开发者_StackOverflowude <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
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
only allocates memory, but does not create an object. So, the line
Aa* aa = (Aa*)malloc(sizeof(Aa));
allocates 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 the vtable
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. Since B
does not contain virtual functions, no such problem arises. It would happen with B
too, however, if B
contained any data-members that require initialization, such as this:
class B
{
public:
B() : foo(new int()) {}
int f() {return *foo;}
private:
int * foo;
};
The line
Aa* aan = (Aa*)new Aa();
can do without the cast:
Aa* aan = new Aa();
The reason is that malloc
knows nothing about C++ constuctors and consequently does not call them. You can call the constuctors yourself using placement new
:
int main()
{
Aa* aa = (Aa*)malloc(sizeof(Aa));
new(aa)Aa;
Aa* aan = (Aa*)new Aa();
Bb* bb = (Bb*)malloc(sizeof(Bb));
new(bb)Bb;
std::cout << bb->f() << std::endl;
std::cout << aan->f() << std::endl;
std::cout << aa->f() << std::endl;
aa->~Aa();
free(aa);
delete aan;
bb->~Bb();
free(bb);
return 0;
}
Note that you have to manually call the destructors before freeing such memory.
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:
struct Foo {
void * vtable;
int aClassMemberVar;
};
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
does not call the constructor of the class, so your object is not initailized properly, hence it seg faults. Use new
to allocate memory when using C++. BTW, there is no need to cast the pointer returned from new
.
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.
精彩评论