【问题标题】:Opaque Type C-pointer to shared_ptr指向 shared_ptr 的不透明类型 C 指针
【发布时间】:2016-01-21 16:34:56
【问题描述】:

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

类型 P 是 public_api.h 中的 typedef-ed 以及一些创建、修改和销毁它的函数,例如。 createP 在下面的 sn-p 中。

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

我的用例简化如下:

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

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

  1. 我可能必须围绕类型 P(可能是每个此类类型)创建一个包装类,该类使用构造函数、成员函数和析构函数来合理地创建、修改和销毁函数。 是否值得麻烦而不是继续使用原始指针?

  2. 有没有其他方法可以解决这个库施加的限制?

更新:

上述情况确实可以使用 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);

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

【问题讨论】:

  • 你想要的词是opaque -> 是基于一个隐藏类型
  • 由于智能指针需要能够创建和删除对象,因此模板类型的构造函数和析构函数的声明需要可见
  • @iharob 感谢您提供的术语,我将使用它并更新帖子

标签: c++ pointers boost smart-pointers


【解决方案1】:

只要库还导出一个函数来破坏不透明类型,这很简单。然后,您可以在智能指针的自定义删除器中使用此功能。

我在这里使用了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);

【讨论】:

  • 谢谢@Richards --- 它就像一个魅力。我至少应该摆弄一下图书馆一次才能弄清楚。该库确实提供了一个删除器,我已经编辑了上面的代码。再次感谢。
  • @bvraghav 很棒。自定义删除器经常被忽视:)
【解决方案2】:

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

例子:

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

【讨论】:

  • 这与我建议 pt 时的感觉非常接近。 1 非常感谢您的实施。实际上,如果我走到这一步,我宁愿将所有接受OpaqueType* 作为第一个参数的函数声明为OpaqueWrapperType 的公共成员,并且根本没有指针实现。但那是我,而不是所有人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-12
  • 2011-02-12
  • 1970-01-01
  • 2011-07-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多