简体   繁体   English

使用指向来自 C 库的结构的智能指针,该库通过 typedef(即不完整的类型)隐藏实现

[英]Using a smart pointer to a struct from a C library which hides the implementation via typedef's (i.e. incomplete type)

I'm trying to use a C library which basically only exposes typedefs to structs that are used internally.我正在尝试使用 C 库,它基本上只将typedefs暴露给内部使用的结构。 The issue is that I want to use smart pointers to manage the lifetime of the raw pointers which are the interface to the library, but I cannot create the smart pointers because of an incomplete_type error.问题是我想使用智能指针来管理作为库接口的原始指针的生命周期,但由于incomplete_type的类型错误,我无法创建智能指针。 Note I have asked a previous question previous question trying to solve the same problem but the question turned out to be a poor representation of my actualy problem:注意我已经问过一个先前的问题, 以前的问题试图解决同样的问题,但这个问题证明我的实际问题的表现很差:

I cannot figure out how to use a smart pointer to the type that I need from the C library.我无法从 C 库中弄清楚如何使用指向我需要的类型的智能指针。 Instead I've been using smart pointers to the underlying raw pointers (see below) but this isn't exactly what I'd like, and probably not ideal.相反,我一直在使用指向底层原始指针的智能指针(见下文),但这并不是我想要的,而且可能并不理想。

Here is some code:这是一些代码:

#include "librdf.h" // the library I need to use


int main() {
    // call necessary to use the librdf library. 
    librdf_world *world = librdf_new_world();
    librdf_world_open(world);

    /* 
     * Error: In instantiation of function template specialization
     * 'std::make_unique<librdf_world_s, librdf_world_s *&>'
     * allocation of incomplete type 'librdf_world_s'
     */
    std::unique_ptr<librdf_world> w1 = std::make_unique<librdf_world>(world);

    /* // errors: 
     * 1) Template argument for template type parameter must be a type // (on librdf_free_world left)
     *
     * 2) No matching function for call to 'make_unique' // (on std::make_unique<librdf_world, librdf_free_world>, right)
     *
     */
    std::unique_ptr<librdf_world, librdf_free_world> w2 = std::make_unique<librdf_world, librdf_free_world>(world);

    /* Error: 
     * In instantiation of template class 'std::unique_ptr<librdf_world_s, void (librdf_world_s *)>'
     * data member instantiated with function type 'void (librdf_world_s *)' // (on w3)
     *
     * No matching function for call to 'make_unique' candidate function template not viable:
     * cannot convert argument of incomplete type 'librdf_world *'
     * (aka 'librdf_world_s *') to 'void (&&)(librdf_world_s *)' for 1st argument // (on std::make_unique<librdf_world, decltype(librdf_free_world)>)
     */
    std::unique_ptr<librdf_world, decltype(librdf_free_world)> w3 = std::make_unique<librdf_world, decltype(librdf_free_world)>(world);


    /* No error: 
     * This version actually works and has been my strategy for a while now. Note,
     * I've been using shared_ptr because I need other objects to have a reference
     * to the `world` to create other objects from the library. An example call to the library would be:
     *     librdf_new_node(world, ... other arguments ... );
     * However using a smart pointer to a raw pointer doesn't solve the problem of automatically
     * managing the lifetime of the underlying raw pointer (according to valgrind). My attempt at
     * overcoming this issue is to wrap the smart pointer in a class and have the shared_ptr as
     * the single private variable. Then, in the destructor, when the shared_ptr::use_count gets to 1
     * I call the C destructor.
     *  i.e.
     *      ~LibrdfWorld(){ // wrapper class name
     *          if (world_.use_count == 1){ // world_ is private instance of shared pointer to librdf_world*
     *              librdf_free_world(*world_.getWorld()); // call the c library destructor when ref count gets to 1
     *          }
     *
     */
    std::shared_ptr<librdf_world*> w4 = std::make_shared<librdf_world*>(world);
}

So what is the best way to use this library from c++?那么从 c++ 使用这个库的最佳方法是什么? Do I use the raw pointers and manage the life times manually?我是否使用原始指针并手动管理生命周期? Do I use the smart pointer to the raw pointer?我是否使用指向原始指针的智能指针? Or is there another way I haven't thought of.或者还有其他我没有想到的方法。

std::make_shared and std::make_unique are used to allocate and then construct objects and return them as shared_ or unique_ pointers. std::make_sharedstd::make_unique用于分配然后构造对象并将它们作为shared_unique_指针返回。 It expects to receive arguments which will be passed to the constructor of your class, and it needs the type to be complete so that it can call this constructor.它期望接收 arguments ,它将被传递给 class 的构造函数,并且它需要类型是完整的,以便它可以调用此构造函数。

In this case, however, the library allocates and constructs the object for you with librdf_new_world() , and you don't even want the behavior of std::make_unique or std::make_shared .但是,在这种情况下,库会使用librdf_new_world()为您分配和构造 object ,您甚至不需要std::make_uniquestd::make_shared的行为。 Simply pass world into the constructor of your smart pointer variable like so只需像这样将world传递给智能指针变量的构造函数

#include "librdf.h"
#include <memory>

int main() {
    // call necessary to use the librdf library. 
    librdf_world *world = librdf_new_world();
    librdf_world_open(world);

    // shared pointer
    std::shared_ptr<librdf_world> w2(world, librdf_free_world);
}

It's probably best to just do it all on one line so your smart pointer is the only reference to the object, that way you don't have to worry about accessing the data after its freed or double freeing it.最好只在一行上完成所有操作,因此您的智能指针是对 object 的唯一引用,这样您就不必担心在数据被释放或双重释放后访问数据。

std::shared_ptr<librdf_world> world(librdf_new_world(), librdf_free_world);
librdf_world_open(world.get());

To get this to work with std::unique_ptr , you need to employ the strategy used in the answer to your previous post , making a default-constructible deleter class and passing that as a template argument to your std::unique_ptr .要使其与std::unique_ptr一起使用,您需要采用上一篇文章的答案中使用的策略,制作一个可默认构造的删除器 class 并将其作为模板参数传递给您的std::unique_ptr

Note, in C++20 mode, you can make a lambda as a deleter inline to accomplish this as well.请注意,在 C++20 模式下,您也可以将 lambda 作为删除器内联来完成此操作。

using WorldPtr = std::unique_ptr<
    librdf_world,
    decltype([](librdf_world* w){librdf_free_world(w);})
>;

WorldPtr world(librdf_make_world);
librdf_world_open(world.get());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 指向类型不完整的 typedef 的指针 - Pointer to a typedef with incomplete type 有什么方法可以获取llvm参考指针值的原始类型(即指针类型) - Is any way to get llvm deference pointer value's raw type(i.e. pointer type) 反转指向成员的指针(即获取包含结构的地址) - Invert pointer to member (i.e. get the address of the containing struct) 在C中使用C ++ struct和虚拟成员(即非POD) - Using C++ struct with virtual members (i.e. non-POD) in C C ++自定义矢量实现–指向不完整类型的指针的下标 - C++ custom vector implementation – subscript of pointer to incomplete type 删除指向不完整类型和智能指针的指针 - Deletion of pointer to incomplete type and smart pointers 在C ++中从C库正确初始化typedef结构 - Initializing typedef struct from C library properly in C++ 初始typedef结构指针(C / C ++) - Initial typedef struct pointer (C/C++) 如何导入或安装预构建的python扩展模块(C ++)(即未通过setuptools编译的库)? - How to import or install pre-built python extension module (C++) (i.e. library not compiled via setuptools)? 在Stack实现中使用哪个智能指针? - Which smart pointer to use in Stack implementation?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM