読者です 読者をやめる 読者になる 読者になる

pimplパターン+コンパイルタイムアサート

pimplパターンは良く使うのだけれど、毎回newするのは如何なものかと思っていた。
コンパイルタイムアサート使ってこんな風に書けばメモリブロックがひとつで済む。

hoge.h
// コントローラ
class Controller
{
public:
    Controller();

    const char* name() const;

private:
    struct DataModel;
    DataModel* const _data;
    int _buffer[0x10 /* >= sizeof(DataModel) */];  // アライン合わせのためにintで。
};
hoge.cpp
#include <string>  // pimplなので.cpp側にincludeできる

// データモデル
struct Controller::DataModel
{
    std::string name;
};

// コンパイルタイムアサート
template<bool T>
struct __compiletime_assert__;
template<>
struct __compiletime_assert__<true> {
    static inline void raise() {}
};
#define COMPILETIME_ASSERT(CONDITION) {__compiletime_assert__<!!(CONDITION)>::raise(); }

Controller::Controller():
    _data(new(_buffer) DataModel())
{
    COMPILETIME_ASSERT(sizeof(DataModel) <= sizeof(_buffer));    // バッファが足りているか確認
}

const char* Controller::name() const
{
    return _data->name.c_str();
}

これならDataModelを書き換えたときに容量がサイズオーバーしたらコンパイルタイムアサートに引っかかる。プロジェクトが大きくなってきてincludeが複雑になるとひとつのヘッダを書き換えただけで大量にビルドされるし、ヘッダにヘッダをインクルードすると芋ヅル式に依存してビルドがどんどん長くなるのでpimplパターンは重要なんだけど、メモリブロックが多くなってメモリが荒れるのも微妙だった。
これはいい。