-2

I am writing a c++ code. As a part of it, I use a C library quickjs. This library allows creating dynamic memory using its custom js_mallocz call (which internally uses malloc), and freeing it later with js_free call.

I have a struct like this :

struct Person{
std::string id;
unsigned short age;
};

Which I have created using js_mallocz call, which is freed using the proper call.

//while assigning
auto person = (Person*) js_mallocz(ctx,sizeof(Person));
sole::uuid u4 =sole::uuid4();
std::string u = u4.base62();
person->id=u;
person->age=40;

//while freeing
js_free(ctx,person);

A code like this would give an error like :

24 bytes in 1 blocks are definitely lost in loss record 1 of 2
==30236==    at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==30236==    by 0x49D93FE: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.29)
==30236==    by 0x11F93B: assign (basic_string.h:1370)
==30236==    by 0x11F93B: operator= (basic_string.h:700)

I can't use new operator as I am required to use the memory allocation done by the third party lib quickjs. How do one free std::string in such struct created using malloc ?

Ken White
  • 123,280
  • 14
  • 225
  • 444
Anurag Vohra
  • 1,781
  • 12
  • 28
  • 3
    malloc will not call the constructors. look up placement new: [https://stackoverflow.com/questions/222557/what-uses-are-there-for-placement-new](https://stackoverflow.com/questions/222557/what-uses-are-there-for-placement-new) – drescherjm Feb 11 '23 at 02:31
  • 1
    Don't use `malloc` in C++. Just don't. – Jesper Juhl Feb 11 '23 at 02:32
  • @JesperJuhl and @drescherjm, I have no choice other than indirectly using malloc. As I use this third party C lib `quickjs` (javascript engine) to manage memory, which internally uses malloc. – Anurag Vohra Feb 11 '23 at 02:37
  • 2
    If you gotta `malloc`, follow through on @drescherjm ENTIRE comment. Note that you have found one of the interesting cases where you will have to manually call the instance's destructor. Much joy. – user4581301 Feb 11 '23 at 02:40
  • 1
    `std::string` is neither trivially default-constructible nor trivially destructible. So if you just use `malloc` to allocate memory, you will not be able to create an object of type `Person` in the allocated memory. (Note that there are some types of objects that can be created implicitly, the implicit lifetime type.) So `person->id = u` will attempt to assign to an object that does not exist. Even if this succeeds, `js_free` will not properly destroy the object because the destructor is not called. – Pluto Feb 11 '23 at 02:45
  • 1
    What do you gain from a dynamic allocation here? If the answer is "I don't know." find out before going much further because if the answer turns out to be "Absolutely nothing." you're taking on extra work and risk for no reward. – user4581301 Feb 11 '23 at 02:48
  • 1
    Ah ha. That's me not reading quite enough. `std::string` will internally use its own allocator to get storage and you can be assured that allocator won't be using `jsmalloc`. You'll either have to make your own allocator or abandon using `std::string`. – user4581301 Feb 11 '23 at 02:51
  • 2
    Useful reading: [std::string with a custom allocator](https://stackoverflow.com/questions/37502974/stdstring-with-a-custom-allocator) – user4581301 Feb 11 '23 at 02:53
  • 1
    You should find whoever told you to use `malloc` in C++ and tell them they are wrong. C++ is an object oriented language, and `malloc` **never** creates an object. – Drew Dormann Feb 11 '23 at 02:57
  • @DrewDormann I am not using malloc, the C library I am using do use malloc inside. I am using the C library which does this. So I am forced to abode by the means its provides. – Anurag Vohra Feb 11 '23 at 03:23
  • @Pluto I am not using malloc, the malloc is used by the C library I am using in my c++ code. I am passing a struct with a string as its member. And valgrind complains memoery loss for that std::string member of that struct. – Anurag Vohra Feb 11 '23 at 03:25
  • 1
    @drescherjm Your comment of using `Placement new` helped me out and solved the issue. – Anurag Vohra Feb 11 '23 at 04:11
  • Great! Consider writing an answer showing what you did. I did not write an answer because although I know to use placement new for this I have never needed to use it in my code. – drescherjm Feb 11 '23 at 04:33
  • 1
    Placement new may solve part of the problem, but I'm pretty sure it's A) not a necessary part and B) missing the `string`'s internal buffer. If you dynamically allocate the `string` itself with `jsmalloc` and placement new it, or automatically allocate it (what I think you should do) If you allow `std::string` to allocate its internal buffer the way it wants to by default, the `string` will **not** use `jsmalloc`. If you have to dynamically allocate with `jsmalloc` you must teach `std::string` to use `jsmalloc` with a custom allocator. – user4581301 Feb 11 '23 at 05:33
  • @drescherjm I feel dishonest on writing answer directly for someone' else suggestion. I would now write answer on your request – Anurag Vohra Feb 11 '23 at 06:34
  • In this scenario I don't think you are worried that the `std::string` uses new internally. It's just that the `js_mallocz()` is needed to allocate the memory for Person to satisfy the c language library. – drescherjm Feb 11 '23 at 13:09

2 Answers2

1

Placement new is the way to solve this issue. (Concluded it based on from comments from @drescherjm) So the code should be :

//while assigning
auto person = (Person*) js_mallocz(ctx,sizeof(Person));
person = new(person) Person(); //Placement new 
sole::uuid u4 =sole::uuid4();
std::string u = u4.base62();
person->id=u;
person->age=40;

//while freeing
person->~Person(); //Manually call destructor
js_free(ctx,person);
Anurag Vohra
  • 1,781
  • 12
  • 28
1

Redefine your global operator new (all relevant varieties) in terms of js_mallocz and corresponding operator delete in terms of js_free.

Placement new is not a solution, because the C++ standard library and any third-party C++ library you happen to use will happily keep allocating memory for their internal needs with operator new. Not even speaking about needing to rewrite all of your code in this horrible style.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • The third party libray is a C library. And hence they use `malloc` for memory allocation. The `placement new` operator do not creates a new memory, it only calls the constructor and store at the same place created by `js_malloc`. juts before freeing memory I need to manually call the destructor as well. – Anurag Vohra Feb 11 '23 at 06:54
  • @AnuragVohra You're thinking too small. If everything dynamically allocated must use `js_malloc` you have to cover all of the allocations you make directly as well as all of the allocations made inside the objects you make. Replacing `new` will cover almost all of the bases. – user4581301 Feb 11 '23 at 19:04
  • @user4581301 The C lib I am using is QuickJS, a javascript engine, which manages memory for all JS object created. If `js_malloc` and `js_free` are used properly, all things related to it are properly released when engiine is shut down. If I resort too `new`, than I need to sync them when JS Object go out of scope in javascript, basically hacking into the engine I have not written and also bind them to be released if engine is shutting down. Overall would be a big mess in my scenario, when `placement new` can do it very easily. – Anurag Vohra Feb 12 '23 at 01:32
  • 1
    Please read up on user-overridable `operator new` and `operator delete`. You either need *all* allocations to go through `js_malloc` and `js_free`, in which case user-overridable `operator new` and `operator delete` are the only option, or need only JS-related allocations to go through `js_malloc` and `js_free`, in which case you should do absolutely nothing with `struct Person`, because it cannot possibly go through your JS engine. – n. m. could be an AI Feb 12 '23 at 06:38