[英]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_shared
和std::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_unique
或std::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.