What is the problem with malloc () and virtual functions?

Possible duplicate:
C ++: why do we need new ?

Why can't 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. He 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 Information: g ++ (Ubuntu / Linaro 4.4.4-14ubuntu5) 4.4.5

+4
source share
7 answers

A common way to implement virtual functions is to point to a "virtual table" or virtual table with a negative offset from the object. This table is needed to figure out which virtual function to call. That is why just the malloc'ing space is not working.

+6
source

malloc only allocates memory but does not create an object. So the line

 Aa* aa = (Aa*)malloc(sizeof(Aa)); 

allocates a memory area that is large enough to hold A but contains garbage. As others have pointed out, this also means that the pointer to the vtable will not be set (I received this comment from @David Rodríguez for another answer), which is required to send calls to virtual functions. Since B does not contain virtual functions, this problem does not occur. This will happen with B , however, if B contains any data items that require initialization, for example:

 class B { public: B() : foo(new int()) {} int f() {return *foo;} private: int * foo; }; 

Line

 Aa* aan = (Aa*)new Aa(); 

can do without broadcasting:

 Aa* aan = new Aa(); 
+6
source

The reason is that malloc does not know anything about C ++ constructors and therefore does not name them. You can directly call constructors using the new placement :

 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 must manually call destructors before freeing such memory.

+6
source

Do not use malloc, use new - malloc does not call constructors.

When you execute A * a = new A(); , the compiler will allocate memory, set the vtable pointer to A, and invoke the constructor. When you call a virtual function, the virtual table is used to actually search for the function.

When you do A * a = (A *) malloc(...); , the compiler will allocate memory that will contain random data. When you call a virtual function, it will look at the (trash) vtable and call a random location.

A class with virtual functions looks something like this:

 struct Foo { void * vtable; int aClassMemberVar; }; 

A virtual function call looks at the "hidden" vtable pointer, which points to the vtable class, a linked list of function pointers. Therefore, this vtable pointer must be initialized, and malloc does not.

+2
source

Of course, because the virtual function table is not created correctly?

+1
source

malloc does not call the constructor of the class, so your object is not initialized properly, therefore, it causes seg errors. Use new to allocate memory when using C ++. BTW, there is no need to throw the pointer returned from new .

0
source

A good reason is called virtual tables. Type objects that have virtual methods have a pointer table that points to the address of the actual virtual methods that should be called. They are called virtual tables or v-tables.

0
source

Source: https://habr.com/ru/post/1343761/


All Articles