【问题标题】:why handle to an object frequently appears as pointer-to-pointer为什么对象的句柄经常显示为指针指针
【发布时间】:2018-08-28 10:26:31
【问题描述】:
将对象句柄设置为指向指针而不是指针的意图是什么?如下代码:
FT_Library library;
FT_Error error = FT_Init_FreeType( &library );
在哪里
typedef struct FT_LibraryRec_ *FT_Library
所以&library 是FT_LIBraryRec_ 类型的句柄FT_LIBraryRec_**
【问题讨论】:
标签:
c
pointers
handle
pointer-to-pointer
【解决方案1】:
这是一种模拟在C中通过引用传递的方法,否则只能通过值传递。
【解决方案2】:
“C”库函数FT_Init_FreeType 有两个输出,错误代码和/或库句柄(它是一个指针)。
在 C++ 中,我们更自然地:
返回一个封装调用成功或失败的对象和库句柄,或者
返回一个输出 - 库句柄,失败时抛出异常。
C API 通常不以这种方式实现。
根据上述情况,C 库函数返回成功代码并传递输入/输出变量的地址以进行条件突变的情况并不罕见。
【解决方案3】:
该方法隐藏了实现。它加快了代码的编译速度。它允许在不破坏使用它们的现有代码的情况下升级库使用的数据结构。最后,它确保该对象的地址永远不会改变,并且您不会复制这些对象。
单指针版本的实现方式如下:
struct FT_Struct
{
// Some fields/properties go here, e.g.
int field1;
char* field2;
}
FT_Error Init( FT_Struct* p )
{
p->field1 = 11;
p->field2 = malloc( 100 );
if( nullptr == p->field2 )
return E_OUTOFMEMORY;
return S_OK;
}
或 C++ 等价物,没有任何指针:
class FT_Struct
{
int field1;
std::vector<char> field2;
public:
FT_Struct() :
field1( 11 )
{
field2.resize( 100 );
}
};
- 作为库的用户,您必须包含结构/类 FT_Struct 定义。库可能非常复杂,因此会减慢代码的编译速度。
- 如果库是动态的,即 Windows 上的 *.dll、Linux 上的 *.so 或 osx 上的 *.dylib,则升级库,如果新版本更改了结构/类的内存布局,旧应用程序将崩溃。
- 由于 C++ 的工作方式,对象是按值传递的,即您通常希望它们是可移动和可复制的,这不一定是库作者想要支持的。
现在考虑以下函数:
FT_Error Init( FT_Struct** pp )
{
try
{
*pp = new FT_Struct();
return S_OK;
}
catch( std::exception& ex )
{
return E_FAIL;
}
}
作为库的用户,您不再需要知道 FT_Struct 里面有什么,甚至不需要知道它的大小。你不需要#include实现细节,即编译会更快。
这与动态库很好地配合,库作者可以随意更改内存布局,只要 C API 稳定,旧应用程序将继续工作。
API 保证您不会复制或移动值,您不能复制未知长度的结构。