Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialization of Class using malloc()

How should a c++ class be used when its memory has been reserved from a C malloc?

I'm using a C library (lua) and I need to expose a C++ class to it, in this case in order to garbage collect these reserved space, lua does the memory reservation.

A simpler similar scenario follows:

#include <string>

class Clase{
private:
    std::string valor;
public:
    Clase(){}
    Clase(const std::string & valor) : valor(valor){}
    const std::string & get() const { return this->valor; }
    void set(const std::string & valor){ this->valor = valor;}
    ~Clase(){}
};

typedef struct
{
    Clase cls;
}Estructura;

int main(int argc, char ** argv)
{
    Estructura * est = (Estructura *) malloc(sizeof(Estructura));

    est->cls.set("Hola");   // First attempt

    Clase myCls;   // Second attempt
    est->cls = myCls;

    return 0;
}

I understand, and have checked, that with malloc the class constructor is not called; that was expected, and so the copy (assign) operator can't be called with an invalid instance (the string inside Class). I suspect that the second attempt fails in the same point, when copying the string inside the Class instance.

So:

  • is it possible to correctly initialize a class instance that had its memory reserved by malloc?
  • what other caveats are there?, vtables?
  • would the free complementary to the malloc leave memory leaks? (I'm guessing that since the Clase destructor won't be called the string won't be correctly freed? [I'm assuming that string holds memory outside the instance itself])

Using pointer for the Clase inside Estructura, works well, is this the best solution?

And as bonus, best way to delete the instance when lua garbage collects it?, using the __gc metamethod or is something better?

like image 940
Javier Mr Avatar asked Dec 19 '22 04:12

Javier Mr


1 Answers

It's a bit odd to use malloc instead of new, but it is possible. You need to use placement new:

void *memory = malloc(sizeof(Estructura));

Estructura *est = new(memory)Estructura;

When you're finished with the object it's your responsibility to call the destructor yourself:

est->~Estructura();

Everything, such as vtables, will be correctly initialized, so there's no need to worry. The awkward bit is dealing with the deletion as you need to destruct the object before releasing the memory via free. delete does this automatically for you, but you'll need to do this yourself.

like image 66
Sean Avatar answered Jan 10 '23 16:01

Sean