Difference between malloc and calloc with std::string

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Difference between malloc and calloc with std::string



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 ?





Consider reading a good book.
– Passer By
Aug 12 at 12:06





Don't use malloc/calloc/realloc/free in C++. Use new/new/delete/delete that properly call constructors/destructors. Or even better, use containers and/or smart pointers. Avoid manual memory management.
– Jesper Juhl
Aug 12 at 12:11



malloc


calloc


realloc


free


new


new


delete


delete





The issues is that you are not constructing the strings which is needed.....If you have your heart set on using malloc you need to placement new the memory you get back before you use it as a string......
– DarthRubik
Aug 12 at 12:13


malloc


new





I think it initializes the string itself It does not construct the string. The way you are using it is UB.
– drescherjm
Aug 12 at 12:45






@TinSlam I have recently gotten into C++ -- What books have you been reading since you are new to C++? No book that I know of introduces a C++ programmer to malloc or calloc in creating objects. Or are you reading C books and applying it to C++? If so, you will make more errors similar to the ones you're making now.
– PaulMcKenzie
Aug 12 at 13:12


malloc


calloc


C




2 Answers
2


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


std::string



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().


malloc()


calloc()


malloc()



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.


std::string



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.


new


malloc


malloc()


new


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





You shouldn't cast the result of new. The pointer is already of correct type.
– user2079303
Aug 12 at 13:05





@user2079303 thanks. The wonders of copy-paste on the phone strike again.
– Michael Veksler
Aug 12 at 13:07



Can somebody explain this behavior ?



The behaviour is undefined in both cases. The calloc case appearing to work is simply due to bad luck.


calloc



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






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

Creating a leaderboard in HTML/JS