今日も配列版make_sharedの話です。指定のアライメントに沿った領域を確保するものを作ってみました。

経緯はこうです。手元に、可変長の領域を確保する目的でboost::shared_array<char> p(new char[n]);などといったコードがありました。これを配列用のboost::make_shared<char[]>に置き換えようとして、アラインメントの考慮が要ることに気付いたというわけです。new char[]と違って、そんな保証あるわけがありません。そこで、自前で作ってみました。

#include <memory> // for std::align
#include <cstddef> // for std::max_align_t
#include <boost/smart_ptr/make_shared_array.hpp>
 
boost::shared_ptr<char[]> make_shared_aligned(
  std::size_t size,
  std::size_t alignment = alignof(std::max_align_t))
{
  std::size_t space = size + alignment - 1;
  auto buffer = boost::make_shared<char[]>(space);
  void* p = buffer.get();
  return boost::shared_ptr<char[]>(
    buffer,
    reinterpret_cast<char*>(std::align(alignment, size, p, space)));
}
 
// ここからサンプルコード
#include <iostream>
#include <cstring>
 
struct hoge
{
  std::size_t length;
  char str[1]; // str[0]~str[length]までの可変長のメンバー
};
 
int main()
{
  auto s = "orange";
  auto x = boost::reinterpret_pointer_cast<hoge>(
    make_shared_aligned(sizeof (hoge) + std::strlen(s)));
  x->length = std::strlen(s);
  std::strcpy(x->str, s);
  std::cout << x->str << std::endl;
}

std::align関数は、指定した大きさの領域の中から指定のアラインメントに適合する場所を返す関数です: align (C++11) – cpprefjp。Boostでも実装されています: Chapter 2. Boost.Align – 1.56.0


なお、maked_shared<T>はshared_ptrを生成するヘルパー関数です。参照カウンタとT型のオブジェクトを一度のメモリ確保で済ませるため、shared_ptr<T>(new T)より効率的です。

現在のところ、今回使ったような配列を確保するmake_sharedはBoostのみで、標準ライブラリstd::make_sharedにはありません:配列版boost::make_shared (Boost 1.53) ‐ イグトランスの頭の中(のかけら)


スポンサード リンク

この記事のカテゴリ

  • ⇒ アラインメント保証付きmake_sharedを作った