指向 shared_ptr 的不透明类型 C 指针
Opaque Type C-pointer to shared_ptr
我遇到了以下情况。(更新:称为不透明类型;感谢信息@iharob)
类型 P 在 public_api.h 中被 typedef
编辑,还有一些创建、修改和销毁它的函数,例如。 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;
}
我想使用智能指针而不是原始指针。在这里,我被困住了。因为,智能指针在实例化时要求类型完整(在boost中用checked_delete.hpp
实现)
我可能必须围绕类型 P(可能是每个这样的类型)创建一个包装器 class,它负责合理地创建、修改和销毁函数,以及构造函数、成员函数, 和析构函数。 是否值得麻烦而不是继续使用原始指针?
有没有其他方法可以解决图书馆强加的这个限制?
更新:
上述情况确实有 shared_ptr 库的解决方案,如@Richard 的答案所示。总之,构造函数需要一个删除器 class,作为 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);
然后整个程序运行正常。并且确实满足用例。
您可以创建一个包装器 class,而不是使用该库,该包装器在其构造函数中分配指针并在其析构函数中释放它,并定义了一个强制转换运算符,只需强制转换即可轻松访问指针。这就是作用域指针的作用,而且实现起来相当简单。
示例:
#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;
}
如果库还导出一个函数来销毁不透明类型,这很容易做到。然后,您可以在智能指针的自定义删除器中使用此功能。
我在这里使用了 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);
我遇到了以下情况。(更新:称为不透明类型;感谢信息@iharob)
类型 P 在 public_api.h 中被 typedef
编辑,还有一些创建、修改和销毁它的函数,例如。 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;
}
我想使用智能指针而不是原始指针。在这里,我被困住了。因为,智能指针在实例化时要求类型完整(在boost中用checked_delete.hpp
实现)
我可能必须围绕类型 P(可能是每个这样的类型)创建一个包装器 class,它负责合理地创建、修改和销毁函数,以及构造函数、成员函数, 和析构函数。 是否值得麻烦而不是继续使用原始指针?
有没有其他方法可以解决图书馆强加的这个限制?
更新:
上述情况确实有 shared_ptr 库的解决方案,如@Richard 的答案所示。总之,构造函数需要一个删除器 class,作为 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);
然后整个程序运行正常。并且确实满足用例。
您可以创建一个包装器 class,而不是使用该库,该包装器在其构造函数中分配指针并在其析构函数中释放它,并定义了一个强制转换运算符,只需强制转换即可轻松访问指针。这就是作用域指针的作用,而且实现起来相当简单。
示例:
#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;
}
如果库还导出一个函数来销毁不透明类型,这很容易做到。然后,您可以在智能指针的自定义删除器中使用此功能。
我在这里使用了 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);