使用智能指针指向 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_shared
和std::make_unique
用于分配然后构造对象,return它们作为shared_
或unique_
指针。它期望接收将传递给 class 的构造函数的参数,并且它需要完整的类型才能调用此构造函数。
然而,在这种情况下,库使用 librdf_new_world()
为您分配和构造对象,您甚至不想要 std::make_unique
或 std::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);
}
可能最好只在一行上完成所有操作,这样您的智能指针就是对该对象的唯一引用,这样您就不必担心在释放或双重释放数据后访问数据。
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());
我正在尝试使用 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_shared
和std::make_unique
用于分配然后构造对象,return它们作为shared_
或unique_
指针。它期望接收将传递给 class 的构造函数的参数,并且它需要完整的类型才能调用此构造函数。
然而,在这种情况下,库使用 librdf_new_world()
为您分配和构造对象,您甚至不想要 std::make_unique
或 std::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);
}
可能最好只在一行上完成所有操作,这样您的智能指针就是对该对象的唯一引用,这样您就不必担心在释放或双重释放数据后访问数据。
std::shared_ptr<librdf_world> world(librdf_new_world(), librdf_free_world);
librdf_world_open(world.get());
要使其与 std::unique_ptr
一起使用,您需要采用在 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());