銀天随筆集 このページをアンテナに追加 RSSフィード Twitter

2010-04-28 信仰「ワンフェーズコンストラクティズム」

Boost.Optional と Boost.InPlaceFactory で初期化遅延

boost::optional<T> は「値 T あるいは無効値」を取ることのできるクラスです。

通常このクラスは、「失敗するかもしれない」関数戻り値として使用されます:

#include <boost/optional.hpp>
#include <iostream>
 
// 例として std::getline を optional で実装してみる
boost::optional<std::string> getline_optional( std::istream& in )
{
  std::string result;
  if( getline( in, result ) )
  {
    // 行の読み取りに成功
    return result;
  }
  
  // 失敗。無効値( boost::none )を返す
  return boost::none;
}

int main()
{
  // cat コマンドっぽい挙動。入力をそのまま垂れ流す
  while( boost::optional<std::string> const s_ = getline_optional( std::cin ) )
  {
    std::string const& s = s_.get();
    std::cout << s << std::endl;
  }
}

これだけでも十分に有用な Boost.Optional ですが、実は、これ以外の用法も有り、

その最たるものが「オブジェクト初期化を遅延する」というもの。

詳しくは「Boost Optional 初期化 遅延」あたりで Google 先生に訊いてみるといいと思いますが、

通常は std::(auto|unique)_ptr を使って行なうような初期化遅延を、

Boost.Optional を使えば、動的メモリ確保をすることなしに実行できたりするのです。


んで、この Boost.Optional による初期化遅延は、余り知られていませんが、

noncopyable なクラスであっても、 in-place factory を使うことで行なうことが出来ます。

#include <iostream>
#include <boost/noncopyable.hpp>
struct hoge
  : private boost::noncopyable
{
  hoge()
  {
    std::cout << "hoge::hoge()\n";
  }
  ~hoge()
  {
    std::cout << "hoge::~hoge()\n";
  }
  
  void foo()
  {
    std::cout << "hoge::foo()\n";
  }
};
 
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
int main()
{
  // hoge オブジェクトの為の領域を確保(未初期化)
  boost::optional<hoge> h;
  
  std::cout << "creating hoge...\n";
  
  // in place factory を使って初期化出来る
  h = boost::in_place();
  
  std::cout << "created.\n";
  
  // ポインタ同様のアロー演算でアクセス(ただし実体はスタック上にある)
  h->foo();
 
  std::cout << "destroying hoge...\n";
  // boost::none を代入することで破棄できる
  h = boost::none;
  std::cout << "destroyed\n";
  
  // 破棄されると未初期化状態に戻る
  
  // また構築出来る
  std::cout << "re-creating hoge...\n";
  h = boost::in_place();
  
  // スコープアウトと共に削除される
}

http://ideone.com/GOlNH


こうすることで、とあるメモリ領域に直接オブジェクトを構築したりできます。

これは pairのpiecewise construction - Faith and Brave - C++で遊ぼう や、

もっと言うと N3059 - Togetter の one-phase construction にも関わる大事な挙動です。

今回は機械的な例ですが、スレッド等のリソース管理や、スコープガードの初期化/解放遅延といった、

いろいろな場面でスマートポインタより気軽に使えるので、積極的に活用するといいと思いました。