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);