[英]Pimpl without the overhead by casting pointers?
使用 PIMPL 习语时,如果动态分配了 pimpled object,我们将遭受双指针重定向,例如,
auto obj = std::make_unique<PimplClass>();
obj->foo(); // Requires dereferencing {obj} and {obj.pimpl}
似乎如果我们强制我们的 class 的客户端通过std::unique_ptr
构造实例,那么我们可以通过将实例指针重铸为某些实现定义的类型来“免费”(即,无需额外的取消引用)拥有 PIMPL 习惯用法在适当的时候:
// Header
struct SelfPimplClass final
{ // No member variables/implementation details.
// ABI stable with respect to changes to the implementation.
void foo();
~SelfPimplClass();
static std::unique_ptr<SelfPimplClass> create();
};
// Implementation
struct SelfPimplClassImpl final
{
int foo,bar,etc;
void fooImpl() { printf("fooImpl()\n"); };
~SelfPimplClassImpl() { printf("~SelfPimplClassImpl()\n"); }
};
std::unique_ptr<SelfPimplClass> SelfPimplClass::create()
{
auto *ptr = new SelfPimplClassImpl();
return std::unique_ptr<SelfPimplClass>(reinterpret_cast<SelfPimplClass *>(ptr));
}
void SelfPimplClass::foo()
{
return reinterpret_cast<SelfPimplClassImpl *>(this)->fooImpl();
}
SelfPimplClass::~SelfPimplClass()
{
reinterpret_cast<SelfPimplClassImpl *>(this)->~SelfPimplClassImpl();
}
在客户端使用堆栈分配变量的应用程序中,与 PIMPL 相比没有优势,但在客户端无论如何都使用动态分配的情况下(例如,因为他们需要std::shared_ptr
),或者在 PIMPL 的情况下实例是从指针访问的,那么上面的代码似乎提供了显着的性能优势(memory 取消引用数量的一半),主要缺点是额外的样板代码(可以通过适当的模板抽象掉)和少量进行强制转换时未定义的行为。
这种方法直接等同于 C 中的常见做法,即使用 void 指针作为不透明类型,该类型在 function 实现中被强制转换为结构。 主要区别在于,我们没有声明面向公众的不透明类型void
,而是将其声明为空结构,以便我们可以提供成员函数。
鉴于 C 程序员几代人一直在使用 void 指针方法来实现与 PIMPL 相同的效果,但只有一个指针重定向,我总是发现令人惊讶的是,在 C++ 中,我们接受了两个重定向。 我是否遗漏了什么,如果没有,这种做法是否有名字,是否在野外使用? 另外,有没有办法避免reinterpret_cast
的未定义行为?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.