如何将unique_ptr与 c 库中分配的数据一起使用

How to use unique_ptr with data allocated within a c library?

本文关键字:分配 数据 一起 unique ptr      更新时间:2023-10-16

我在 c++ 中,我正在围绕 c 库编写一个包装器。我正在使用的 c 库函数将类型"LDAPMessage **"作为参数,它将在函数中为您分配内存。正常用法如下所示:

LDAPMessage * msg;
c_lib_function(&msg); // allocates the memory for me

现在我想在这种情况下使用unique_ptr,带有自定义删除器。假设我的删除器"LDAPMessageDeleter"存在并在下面工作。

unique_ptr<LDAPMessage*, LDAPMessageDeleter> msg_ptr(new LDAPMessage*);
c_lib_function(msg_ptr.get());

虽然这为我编译,但我遇到了一个 seg 错误。这段代码会不会有问题?这是unique_ptr的正确用法吗?

这样做

可能更容易,例如

LDAPMessage* msg;
c_lib_function(&msg);
// Now we have out pointer (hopefully)
std::unique_ptr<LDAPMessage, LDAPMessageDeleter> msg_ptr(msg);

当然,LDAPMessageDeleter必须调用适当的函数来释放内存(例如 free是内存分配了 malloc )。


您在问题中显示的代码的问题在于,您尝试创建指向指针的指针,但不要使该第一级指针实际指向任何地方。

你在代码中有效地执行的是:

LDAPMessage** msg;
c_lib_function(msg);

C 库中发生的事情是指针是"通过引用"传递的。由于 C 实际上没有适当的引用,因此它可以通过传递指针来模拟。传递对指针的"引用"是通过使用地址运算符传递指针的地址(然后成为指向指针的指针)来完成的。

SO 聊天中的某个人像这样开发了有价值的代码,我再也找不到了:

//ptrptr magic
#include <memory>
template<class T, class deleter>
class ptrptr_type {
public:
    ptrptr_type(std::unique_ptr<T, deleter>& ptr) 
        : uptr(&ptr), tptr(ptr.get()) {}
    ~ptrptr_type() {if (uptr->get()!=tptr) uptr->reset(tptr);}
    operator T**() {return &tptr;}
private:
    std::unique_ptr<T, deleter>* uptr;
    T* tptr;
};
template<class T, class D>
ptrptr_type<T,D> ptrptr(std::unique_ptr<T, D>& ptr) { return {ptr};}

这个ptrptr的用法非常简单:

std::unique_ptr<LDAPMessage, LDAPMessageDeleter> my_ptr; //can be null or initialized, whichever
c_lib_function(ptrptr(my_ptr)); //use ptrptr(my_ptr) whenever you need a T**

就是这样。 真的很简单。 http://coliru.stacked-crooked.com/a/644ed001ffd547ae

发生的情况是ptrptr(my_ptr)堆栈上创建一个临时ptrptr_type,该从unique_ptr中获取指针。 然后,ptrptr公开指向其内部指针的指针,C 函数可以自由修改该指针。 之后,临时ptrptr_type被销毁,其析构函数将指针的新值放回原始unique_ptr

这不是指针到指针的正确用法。该函数获取指向未初始化指针的指针并填充它。在您的第一个示例中,这是一个局部变量。如果您希望它由 unique_ptr 管理,它应该仍然是一个本地的,只是包含在 unique_ptr 对象中。

LDAPMessage * msg;
c_lib_function(&msg); // allocates the memory for me
std::unique_ptr< LDAPMessage, LDAPMessageDeleter > // This type contains a ptr
               msg_ptr( msg ); // transfer ownership to C++

LDAPMessageDeleter应该收到一个LDAPMessage *,必要时传递给库释放,否则传递给free()