我的问题的实质是:
在c函数中创建新对象的最佳方法是什么,并将对该新对象的引用传递给调用者?
我的整体设置有点复杂,涉及混合的c和c ++代码,因此我提供了一些背景信息:
我正在为3D引擎创建一个c ++库。 该库旨在从不同平台上的主机应用程序中使用。
为了便于兼容性,我现在打算在普通c中隐藏API背后的所有c ++代码。 到目前为止,这种方法运作良好。
我唯一不确定的是,这是通过我的c API实际创建我的引擎实例的最佳方式。
我的第一个方法是:
// 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);
我希望myEngineCreate(void * myEngine)
将我新创建的对象的地址分配给myEngine
。但是在函数返回后,myEngine
仍然指向NULL。为什么呢?
现在我的第二种方法就是:
// 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);
这很有效。 myEngineCreate()
给了我一个指向我的引擎实例的不透明指针,我可以在后续的绘图调用中使用它,我也可以将其发送给我的释放函数,当我完成它时清理内存。
这种方法的问题是,我的探查器抱怨myEngineCreate()
中的内存泄漏。
我知道在一个地方创建一个对象并在另一个地方拥有它是一件微妙的事情,我似乎在这里做错了什么 - 但是什么呢?
提前感谢任何建议或帮助。
答案 0 :(得分:8)
让我们带你的myEngineCreate
功能:
void myEngineCreate(void * myEngine) {
myEngine = new Engine;
}
这不起作用,因为myEngine
是myEngineCreate
函数范围内的局部变量。要在C中传递“通过引用”指针,您必须将其作为指针传递给指针,并使用derefernece运算符指定指针:
void myEngineCreate(void ** myEngine) {
*myEngine = new Engine;
}
您可以使用指针的地址运算符&
来调用它:
void * myEngine;
myEngineCreate(&myEngine);
答案 1 :(得分:2)
在c函数中创建新对象的最佳方法是什么,并将对该新对象的引用传递给调用者?
在C中,最好的,面向对象的方法是创建一个不完整类型的对象,也称为opaque类型(void指针不是一个opaque类型,它只是一个原始地址。)
示例:
// engine.h
typedef struct engine_t engine_t;
engine_t* engine_create (void);
// engine.c
struct engine_t
{
/* all variables placed here will have true private encapsulation */
};
engine_t* engine_create (void)
{
return malloc(sizeof(engine_t));
}
// main.c
int main()
{
engine_t* my_engine = engine_create();
}
这是C中真正的面向对象,没有C ++语言支持,你可以实现最好的面向对象。调用者将无法访问结构的任何成员。
但是在函数返回后,myEngine仍然指向NULL。为什么呢?
因为指针本身是通过C和C ++中的值传递的。您必须传递指针的地址或将指针返回给调用者。有关此主题的多个问题和常见问题解答可以在SO上轻松找到。
答案 2 :(得分:1)
我使用不透明指针做了类似的事情:
typedef struct my_c_engine *myCEngine;
extern "C" myCEngine createEngine() {
return reinterpret_cast<myCEngine>(new myRealEngineClass());
}
extern "C" void releaseEngine(myCEngine c) {
if(c) {
myRealEngineClass *x = reinterpret_cast<myRealEngineClass*>(c);
delete x;
}
}
我这样做是因为我希望C部分完全隔离。