Chiharu の日記

絵描き C/C++ プログラマーの日記です。

std::make_shared 〜ただのヘルパじゃない!

C++0x のスマート ポインタの中で、私が一番良く使うのは std::shared_ptr です。

std::shared_ptr<Image> foo1(const std::uint32_t iWidth, const std::uint32_t iHeight, const std::size_t iRowbytes)
{
 std::shared_ptr<Image> aImage(new Image(iWidth, iHeight, iRowbytes));
 foo2(aImage->getPixelData(), aImage->getWidth(), aImage->getHeight());
 return aImage;
}

こんな感じで使うのですが、C++0x には std::shared_ptr 構築用ヘルパとして std::make_shared メソッドが提供されていることを、つい先ほど知りました。

std::shared_ptr<Image> foo1(const std::uint32_t iWidth, const std::uint32_t iHeight, const std::size_t iRowbytes)
{
 auto aImage = std::make_shared<Image>(iWidth, iHeight, iRowbytes);
 foo2(aImage->getPixelData(), aImage->getWidth(), aImage->getHeight());
 return aImage;
}

こんな感じで使うのですが、これ、タイプ数が減るだけでなく、処理速度向上に貢献するというすぐれものヘルパです。
std::shared_ptr は、コンストラクタで、参照カウンタを管理するオブジェクト ホルダとカスタム デリーターを new するのですが、ポインタごときがポインタとしての振る舞いのためにリソースを動的確保するオーバーヘッドが結構気になっていました。しかし、std::make_shared メソッドは、管理対象のインスタンス用メモリ領域を確保する際に、オブジェクト ホルダとカスタム デリーター用のメモリ領域も一緒に連続領域に確保してくれるようです。
メモリの並びとして、継承なしで参照カウンタをインスタンスに埋め込むような形になるわけですね。すごくイイ!って思います。
あー。こんな最適化、以前の仕事の案件でもやりました。あれは C++ ではなく C で、全てのインスタンス生成にアロケータ指定できるようにして、むりくり連続アドレスに複数のインスタンスを埋め込んでました。懐かしい思い出です。まぁ、L1 キャッシュしかないような環境だと、パフォーマンスの観点から L1 キャッシュの 1-way にワークを収めるというのが意外と大切で。