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

boost::optional は「値 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 にも関わる大事な挙動です。
今回は機械的な例ですが、スレッド等のリソース管理や、スコープガードの初期化/解放遅延といった、
いろいろな場面でスマートポインタより気軽に使えるので、積極的に活用するといいと思いました。