I have recently gotten into C++ and I've encountered a problem working with malloc. The code below does not print out "Success" (Program crashes with exit code 0xC0000005) whereas if I use calloc instead everything works fine.
int main(){
std::string* pointer = (std::string*) malloc(4 * sizeof(std::string));
for(int i = 0; i < 4; i++){
pointer[i] = "test";
}
std::cout << "Success" << std::endl;
return 0;
}
The code below works.
calloc(4, sizeof(std::string));
Malloc also works if I allocate like 12 times the normal amount.
Can somebody explain this behavior ? Does this have something to do with std::string ?
std::string* pointer = (std::string*) malloc(4 * sizeof(std::string));
This only allocates memory sufficient to hold 4 string objects. It does not construct them, and any use before construction is undefined.
EDIT: As for why it works with calloc: most likely, the default constructor of std::string
sets all fields to zero. Probably calloc simply happens to do the same as std::string default construction on your system. In contrast, small malloc() objects are probably allocated with an initial junk, so the objects are not in a valid state
With a big enough malloc()
the effect is similar to calloc()
. When malloc()
can't reuse previously allocated block (with potential junk) it requests new blocks from the operating system. Usually the OS will clear any block it hands to the application (to avoid information leak), making big malloc() behave like calloc().
This won't work on all systems and compilers. It depends on how the compiler implements std::string
and depends on how undefined behavior may confuse the compiler. This means that if it works on your compiler today, it might not work on a different system, or with a newer compiler. Worse, it might stop working on your system with your compiler, after you edit seemingly unrelated code in your program. Never rely on undefined behavior.
The simplest solution is to let C++ deal with allocation and construction, and later with destruction and deallocation. This automatically done by
std::vector<std::string> str_vec(4);
If you insist on allocating and deallocating your own memory (which is a bad idea 99.9% of the time), you should use new
rather than malloc
. Unlike malloc()
, using new
actually constructs the objects.
// better use std::unique_ptr<std::string[]>
// since at least it automatically
// destroys and frees the objects.
std::string* pointer = new std::string[4];
... use the pointer ...
// better to rely on std::unique_ptr to auto delete the thing.
delete [] pointer;
If for some bizarre reason you still want to use malloc (which is a bad idea 99.99% of the time), you must construct and destruct the objects by yourself:
constexpr int size = 4;
std::string* pointer = (std::string*) malloc(size * sizeof(std::string));
for (int i=0; i != size ;++i)
// placement new constructs the strings
new (pointer+i) std::string;
... use the pointer ....
for (int i=0; i != size ;++i)
// destruct the strings
pointer[i].~string();
free(pointer);
Can somebody explain this behavior ?
The behaviour is undefined in both cases. The calloc
case appearing to work is simply due to bad luck.
In order to use an object in allocated space of memory, you must first construct the object. You never constructed any string objects.
Simplest way to construct a dynamically allocated array of objects is to use a vector:
std::vector<std::string> vec(4);
User contributions licensed under CC BY-SA 3.0