Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a C++ string in a structure when malloc()-ing the same structure?

I wrote the following example program but it crashes with segfault. The problem seems to be with using malloc and std::strings in the structure.

#include <iostream>
#include <string>
#include <cstdlib>

struct example {
 std::string data;
};

int main() {
 example *ex = (example *)malloc(sizeof(*ex));
 ex->data = "hello world";
 std::cout << ex->data << std::endl;
}

I can't figure out how to make it work. Any ideas if it's even possible to use malloc() and std::strings?

Thanks, Boda Cydo.

like image 951
bodacydo Avatar asked Aug 05 '10 04:08

bodacydo


2 Answers

You can't malloc a class with non-trivial constructor in C++. What you get from malloc is a block of raw memory, which does not contain a properly constructed object. Any attempts to use that memory as a "real" object will fail.

Instead of malloc-ing object, use new

example *ex = new example;

Your original code can be forced to work with malloc as well, by using the following sequence of steps: malloc raw memory first, construct the object in that raw memory second:

void *ex_raw = malloc(sizeof(example));
example *ex = new(ex_raw) example;

The form of new used above is called "placement new". However, there's no need for all this trickery in your case.

like image 85
AnT Avatar answered Oct 15 '22 15:10

AnT


For a class or struct such as your example, the correct answer is use new not malloc() to allocate an instance. Only operator new knows how to call the constructors for the struct and its members. Your problem is caused by the string member not having ever been constructed.

However, there are rare cases where it is important that a particular patch of memory act as if it holds an instance of a class. If you really have such a case, then there is a variation of operator new that permits the location of the object to be specified. This is called a "placement new" and must be used with great care.

void *rawex = malloc(sizeof(example));  // allocate space
example ex = new(rawex) example();      // construct an example in it
ex->data = "hello world";               // use the data field, not no crash
// time passes
ex->~example();                         // call the destructor
free(rawex);                            // free the allocation

By using placement new, you are obligated to provide a region of memory of the correct size and alignment. Not providing the correct size or alignment will cause mysterious things to go wrong. Incorrect alignment is usually quicker to cause a problem but can also be mysterious.

Also, with a placement new, you are taking responsibility for calling the destructor by hand, and depending on the origin of the memory block, releasing it to its owner.

All in all, unless you already know you need a placement new, you almost certainly don't need it. It has legitimate uses, but there are obscure corners of frameworks and not everyday occurrences.

like image 4
RBerteig Avatar answered Oct 15 '22 15:10

RBerteig