Pimpl成语不使用动态内存分配

ere*_*der 28 c++ embedded pimpl-idiom dynamic-memory-allocation

我们想在项目的某些部分使用pimpl习语.项目的这些部分也恰好是禁止动态内存分配的部分,这个决定不在我们的控制范围内.

所以我要问的是,在没有动态内存分配的情况下,有没有一种干净又好的方法来实现pimpl习语?

编辑
以下是一些其他限制:嵌入式平台,标准C++ 98,没有外部库,没有模板.

Mat*_* M. 25

警告:此处的代码仅显示存储方面,它是一个骨架,没有动态方面(构造,复制,移动,销毁)已被考虑在内.

我建议使用C++ 0x新类的方法aligned_storage,这正是为了拥有原始存储.

// header
class Foo
{
public:
private:
  struct Impl;

  Impl& impl() { return reinterpret_cast<Impl&>(_storage); }
  Impl const& impl() const { return reinterpret_cast<Impl const&>(_storage); }

  static const size_t StorageSize = XXX;
  static const size_t StorageAlign = YYY;

  std::aligned_storage<StorageSize, StorageAlign>::type _storage;
};
Run Code Online (Sandbox Code Playgroud)

在源代码中,然后执行检查:

struct Foo::Impl { ... };

Foo::Foo()
{
  // 10% tolerance margin
  static_assert(sizeof(Impl) <= StorageSize && StorageSize <= sizeof(Impl) * 1.1,
                "Foo::StorageSize need be changed");
  static_assert(StorageAlign == alignof(Impl),
                "Foo::StorageAlign need be changed");
  /// anything
}
Run Code Online (Sandbox Code Playgroud)

这样,虽然您必须立即更改对齐(如果需要),但只有在对象更改太多时才会更改大小.

显然,由于检查是在编译时,你不能错过它:)

如果您无法访问C++ 0x功能,则TR1名称空间中有等效项aligned_storage,alignof并且存在宏的实现static_assert.

  • @Gart:"Foo"大小的任何变化都会引入二进制不兼容性,这就是我们在这里要防止的.因此,你需要*StorageSize*优于`sizeof(Impl)`*和*stable,因此你可能会略微超大它,以便稍后能够将字段添加到`Impl`.然而,你可能会过度过度并最终得到一个非常大的物体......没什么,所以我建议你检查一下你是不是最终得到一个过大的物体,使用这个10%的余量. (3认同)
  • 我需要在构造函数中调用`new(&_storage)Impl();`以使Pimpl成员正确初始化. (2认同)

jde*_*aan 8

pimpl基于指针,您可以将它们设置到分配对象的任何位置.这也可以是cpp文件中声明的对象的静态表.pimpl的要点是保持接口稳定并隐藏实现(及其使用的类型).

  • 必须事先决定最大数量的对象不是错误,这是一个功能.这是禁止动态内存分配的规则背后的主要原理之一.这样做,你永远不会耗尽内存.你永远不必担心碎片堆积. (3认同)
  • 恕我直言,这种方法的唯一缺点是你必须事先/在编译时就这种类型的最大对象数达成一致.对于我能想到的所有其他方面,达到了pimpl的目标. (2认同)