代码之家  ›  专栏  ›  技术社区  ›  Finley

为什么对象的句柄经常显示为指向指针的指针

  •  3
  • Finley  · 技术社区  · 6 年前

    将对象的句柄设置为指向指针而不是指向指针的指针的意图是什么?如下代码:

    FT_Library library;
    FT_Error error = FT_Init_FreeType( &library );
    

    在哪里?

    typedef struct FT_LibraryRec_  *FT_Library
    

    所以 &library 是一个 FT_LIBraryRec_ 类型句柄 FT_LIBraryRec_**

    3 回复  |  直到 6 年前
        1
  •  2
  •   Richard Hodges    6 年前

    “c”库函数 FT_Init_FreeType 有两个输出,错误代码和/或库句柄(指针)。

    在C++中,我们更自然的是:

    • 返回封装调用和库句柄的成功或失败的对象,或者

    • 返回一个输出-库句柄,并在失败时引发异常。

    C API通常不以这种方式实现。

    C库函数返回一个成功的代码,并根据上面的情况有条件地改变传入/传出变量的地址,这是很正常的。

        2
  •  5
  •   Some programmer dude    6 年前

    这是一种方法 模仿 在C中传递引用,否则只有传递值。

        3
  •  1
  •   Soonts    6 年前

    这种方法隐藏了实现。它加速了代码的编译。它允许升级库使用的数据结构,而不破坏使用它们的现有代码。最后,它确保该对象的地址永远不会更改,并且您不会复制这些对象。

    这里是如何实现单指针版本的方法:

    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 );
        }
    };
    
    1. 作为库的用户,必须包含结构/类FT结构定义。库可能非常复杂,因此这会减慢代码的编译速度。
    2. 如果库是动态的,即Windows上的*.dll、*.so Linux上的*.dylib或OSX上的*.dylib,则升级库,如果新版本更改了结构/类的内存布局,则旧应用程序将崩溃。
    3. 由于C++的工作方式,对象是按值传递的,也就是说,您通常期望它们是可移动的和可复制的,这不一定是库作者想要支持的。

    现在考虑以下函数:

    FT_Error Init( FT_Struct** pp )
    {
        try
        {
            *pp = new FT_Struct();
            return S_OK;
        }
        catch( std::exception& ex )
        {
            return E_FAIL;
        }
    }
    

    作为库的用户,您不再需要知道ft结构中的内容,甚至不需要知道它的大小。你不需要 #include 实现细节,即编译速度更快。 这与动态库很好地配合,库作者可以随意更改内存布局,只要C API稳定,旧的应用程序就会继续工作。 API保证您不会复制或移动值,您可以复制长度未知的结构。