shared_ptrでCOW
昨日はベクタのコピーを避けるようにしたわけですが、bjam_grammarでクロージャを使い出すとどうしてもコピーが発生してしまうので、Copy On Write(COW)の最適化を施すことにしました。
<hamigaki/bjam/util/list.hpp>
実装にはboost::shared_ptrを使っていて、必要に応じてオブジェクトをクローニングしています。
class string_list { private: typedef std::vector<std::string> impl_type; public: void push_back(const std::string& s) { if (pimpl_.get() == 0) pimpl_.reset(new impl_type(1u, s)); else if (pimpl_.unique()) pimpl_->push_back(s); else { // オブジェクトを共有しているので、コピーを作成 boost::shared_ptr<impl_type> tmp(new impl_type(*pimpl_)); tmp->push_back(s); pimpl_.swap(tmp); // コミット } } // ... private: boost::shared_ptr<impl_type> pimpl_; };
ちなみに最初に書いたバージョンは、
class string_list { private: typedef std::vector<std::string> impl_type; public: void push_back(const std::string& s) { if (pimpl_.get() == 0) pimpl_.reset(new impl_type(1u, s)); else { unique(); pimpl_->push_back(s); // ここで例外が発生したら取り消せない } } // ... private: boost::shared_ptr<impl_type> pimpl_; // オブジェクトを変更する前に呼ぶ関数(のつもり) void unique() { if (!pimpl_.unique()) { boost::shared_ptr<impl_type> tmp(new impl_type(*pimpl_)); pimpl_.swap(tmp); } } };
となっていて、例外安全性に問題があったので修正しました。