指向shared_ptr的不透明类型 C 指针

Opaque Type C-pointer to shared_ptr

本文关键字:类型 指针 不透明 shared ptr 指向      更新时间:2023-10-16

我遇到了以下情况。(更新:称为不透明类型;感谢您提供的信息@iharob)

P型在public_api.h中typedef-ed,以及一些创建,修改和销毁它的函数,例如。 createP在以下代码片段中。

但是,它的实现基于隐藏类型。隐藏,因为它在通常作为编译二进制文件提供的源代码中定义,可以安装。每个此类操作都依赖于指针类型转换。

我的用例简化如下:

#include <iostream>
using std::cerr;
#include <boost/shared_ptr.hpp>
/* defined in **public** api */
// _PUB_API_ {{{
typedef struct P P;
P* createP();
// }}} _PUB_API_
/* defined in **implementation** files, that are compiled to binary */
// HID_IMPL {{{
typedef struct P_ P_;
struct P_ {};
P* createP() { return (P*) new P_(); }
// }}} HID_IMPL
/* **Use case** */
int main(int argc, char *argv[])
{
  P* p = createP();
  if (p == NULL)
  { /* does not execute */
    cerr << "Unable to create P" << 'n';
    return 1;
  }
  typedef boost::shared_ptr<P> PpointerT;
  //typedef boost::scoped_ptr<P> PpointerT;
  PpointerT ptr = PpointerT(createP(), &deleteP); // compilation error
  if (!ptr)
  {
    cerr << "Error creating shared pointer PpointerT" << 'n';
    return 2;
  }
  cerr << "P created!" << 'n'
       << "PpointerT created!" << 'n';
  return 0;
}

我想使用智能指针而不是原始指针。在这里,我被困住了。因为,智能指针要求类型在实例化时完成(使用 checked_delete.hpp 在 boost 中实现)

  1. 我可能必须围绕类型P(也许是每个这样的类型)创建一个包装类,该类负责使用构造函数,成员函数和析构函数合理地创建,修改和销毁函数。比起使用原始指针,值得

  2. 麻烦吗?
  3. 还有其他方法可以解决库施加的这种限制吗?

更新:

上述情况确实有一个解决方案,shared_ptr库,如答案所示,由@Richard。总而言之,构造函数需要一个删除器类,它充当OpaqueType*的销毁函子,例如:

// Update:PUB_API
void deleteP(P* p);
// Update:HID_IMPL
void deleteP(P* p) { delete (P*) p; } // I don't know if type casting
                                      // here is necessary?
PpointerT ptr = Ppointer(createP(), &deleteP);

然后整个程序运行良好。并且确实满足用例。

这很容易做到,前提是库还导出一个函数来销毁不透明类型。然后,您可以在智能指针的自定义删除器中使用此函数。

我在这里使用了std::聪明的指针,但原则也适用于boost

例:

// included from library:
struct Foo;
Foo* make_foo();
void destroy_foo(const Foo*);

// your code:
auto my_foo_ptr = std::shared_ptr<Foo>(make_foo(), &destroy_foo);

// or unique_ptr:
auto unique_foo = std::unique_ptr<Foo, void(*)(const Foo*)>(make_foo(),
                                                            &destroy_foo);

您可以创建一个包装类,而不是使用该库,该包装类在其构造函数中分配指针,并在它的析构函数中解除分配它,并定义一个强制转换运算符,以便通过强制转换轻松访问指针。这就是作用域指针的作用,实现起来相当简单。

例:

#include <iostream>
class ScopedCharPointer
{
public:
    ScopedCharPointer(size_t size);
    ~ScopedCharPointer();
    operator char *();
private:
    char *pointer;
};
ScopedCharPointer::ScopedCharPointer(size_t size) :
    pointer(new char[size])
{
}
ScopedCharPointer::~ScopedCharPointer()
{
    delete[] pointer;
}
ScopedCharPointer::operator char *()
{
    return pointer;
}
int
main(void)
{
    ScopedCharPointer example(100);
    char *pointer = static_cast<char *>(example);
    std::cout << static_cast<void *>(pointer) << std::endl;
    return 0;
}