boost::optional
通常このクラスは、「失敗するかもしれない」関数の戻り値として使用されます:
#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(); // スコープアウトと共に削除される }
こうすることで、とあるメモリ領域に直接オブジェクトを構築したりできます。
これは pairのpiecewise construction - Faith and Brave - C++で遊ぼう や、
もっと言うと N3059 - Togetter の one-phase construction にも関わる大事な挙動です。
今回は機械的な例ですが、スレッド等のリソース管理や、スコープガードの初期化/解放遅延といった、
いろいろな場面でスマートポインタより気軽に使えるので、積極的に活用するといいと思いました。