繁体   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)

我正在尝试使用 C 库,它基本上只将typedefs暴露给内部使用的结构。 问题是我想使用智能指针来管理作为库接口的原始指针的生命周期,但由于incomplete_type的类型错误,我无法创建智能指针。 注意我已经问过一个先前的问题, 以前的问题试图解决同样的问题,但这个问题证明我的实际问题的表现很差:

我无法从 C 库中弄清楚如何使用指向我需要的类型的智能指针。 相反,我一直在使用指向底层原始指针的智能指针(见下文),但这并不是我想要的,而且可能并不理想。

这是一些代码:

#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);
}

那么从 c++ 使用这个库的最佳方法是什么? 我是否使用原始指针并手动管理生命周期? 我是否使用指向原始指针的智能指针? 或者还有其他我没有想到的方法。

std::make_sharedstd::make_unique用于分配然后构造对象并将它们作为shared_unique_指针返回。 它期望接收 arguments ,它将被传递给 class 的构造函数,并且它需要类型是完整的,以便它可以调用此构造函数。

但是,在这种情况下,库会使用librdf_new_world()为您分配和构造 object ,您甚至不需要std::make_uniquestd::make_shared的行为。 只需像这样将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);
}

最好只在一行上完成所有操作,因此您的智能指针是对 object 的唯一引用,这样您就不必担心在数据被释放或双重释放后访问数据。

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

要使其与std::unique_ptr一起使用,您需要采用上一篇文章的答案中使用的策略,制作一个可默认构造的删除器 class 并将其作为模板参数传递给您的std::unique_ptr

请注意,在 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM