The essence of my question is this:
What is the best approach for creating a new object in a c function and pass some reference to that new object to the caller?
My overall setting is a bit more complex and involves mixed c and c++ code, so I am including some background information:
I am creating a c++ library for a 3D engine. The library is intended to be used from host applications on different platforms.
For easy compatibility reasons I now intent to hide all c++ code behind an API in plain c. This works pretty well so far.
The only thing I am not sure about is, which is the best way for actually creating my engine instance through my c API.
My first approach was this:
// in myEngineAPI.h
void myEngineCreate(void * myEngine);
void myEngineRelease(void * myEngine);
// in myEngineAPI.cpp
#include "myEngineAPI.h"
#include "myPrivateCppEngine.h"
void myEngineCreate(void * myEngine) {
myEngine = new Engine; // <- this doesn't seem to work as expected
}
void myEngineRelease(void * myEngine) {
delete ((Engine *)myEngine);
}
// in my host application
#include "myEngineAPI.h"
void * myEngine = NULL;
myEngineCreate(myEngine); // <- problem: myEngine is still NULL after this line.
// ...draw some fancy stuff...
myEngineRelease(myEngine);
I would expect that myEngineCreate(void * myEngine)
would assign the address of my newly created object to myEngine
. But after the function returns, myEngine
still points to NULL. Why?
Now my second approach was this:
// in myEngineAPI.h
void * myEngineCreate();
void myEngineRelease(void * myEngine);
// in myEngineAPI.cpp
#include "myEngineAPI.h"
#include "myPrivateCppEngine.h"
void * myEngineCreate() {
return new Engine; // <- ok, the function returns a valid pointer
}
void myEngineRelease(void * myEngine) {
delete ((Engine *)myEngine);
}
// in my host application
#include "myEngineAPI.h"
void * myEngine = myEngineCreate(); // <- yay, I have a void pointer to my engine
// ...draw some fancy stuff...
myEngineRelease(myEngine);
This works. myEngineCreate()
gives me an opaque pointer to my engine instance, which I can use in my subsequent drawing calls and which I can also hand to my release function that cleans up memory when I'm done with it.
The problem with this approach is, that my profiler complains about a memory leak in myEngineCreate()
.
I understand that creating an object in one place and owning it in another is a delicate business, and I seem to do something wrong here - but what?
Thanks in advance for any advice or help.
Lets take your myEngineCreate
function:
void myEngineCreate(void * myEngine) {
myEngine = new Engine;
}
This does not work because myEngine
is a local variable within the scope of the myEngineCreate
function. To pass a pointer "by reference" in C you have to pass it as a pointer to a pointer, and use the derefernece operator to assign to the pointer:
void myEngineCreate(void ** myEngine) {
*reinterpret_cast<Engine**>(myEngine) = new Engine;
}
And you call it by using the address-of operator &
of a pointer:
void * myEngine;
myEngineCreate(&myEngine);
As a late addendum, another possible solution is to return the new pointer:
void* myEngineCreate() {
return reinterpret_cast<void*>(new Engine);
}