先ほど Twitter において new 談義で花が咲いていたのですが,この際に「どういう場面で new を使うべきなのだろう?」と,ふと疑問に思いました.そこで,今回は「new を使う場面」を挙げてみようと思います.尚,ほとんど何も分からないまま書くので誰かの補足に期待します:p
多態性 (Polymorphism) を確保したい場合
まず始めに思いつくのが多態性を確保する場合です.例えば,AbstractFactory パターンのようなものを実現する際には new が必要となります.
class Shape { ... }; class Triangle : public Shape { ... }; class Rectangle : public Shape { ... }; Shape* shape_factory(const std::string& name) { if (name == "Triangle") return new Triangle(); else if (name == "Rectangle") return new Rectangle(); return NULL; }
NULL を使用したい場合
これは,正確に言うとポインタを使いたい場合かもしれませんが,オプション的なオブジェクトである(あってもなくても良い),何らかの関数が生成に失敗した事を NULL で知らせるなどの理由で NULL を使用したい場合があります.この場合に new を使用する必要が出てくるかもしれません.
class foo { public: foo() : opt_(NULL) {} void setopt(Object* opt) { opt_ = opt; } ... private: Object* opt_; };
Object* create_object(...) { if (expr) return new Object(...); return NULL; }
これ(特に後者)の代替手段については,Boost.Optional などが挙げられます.また,クラス自体に「生成されたオブジェクトが有効であるかどうか」を調べるメソッドを用意すると言う方法を取る事も選択肢の一つです (e.g., fstream::is_open()).
コピーできないオブジェクトの場合
コピーできないオブジェクトを様々なクラスから参照する場合,そのオブジェクトを new で生成した後,このオブジェクトを利用するクラスはポインタ経由で参照すると言う形を取る事があります.ただし,単に「コピーできない」事だけが問題である場合には,以下のように参照型で受け取る形にできないかをまず検討した方が良いかもしれません.
class foo { public: explicit foo(object& x) : x_(x) {} ... private: object& x_; };
また,関連した問題として,コピー不可能ではないのだけど(パフォーマンスの問題などで)コピーコンストラクタが走って欲しくないような場合も挙げられます.こちらは,コンテナにオブジェクトを格納する場合にしばしば問題として取り上げられる話かなと思います.こちらに関しては,C++0x で rvalue reference と言う機能が組み込まれるので,それによって多くの部分は解消されていくだろうとは思います(参考:本の虫: rvalue reference 完全解説).
new のご使用は計画的に
今のところ思いついたのはこれ位です.いずれにしても,
- ユーザに new を強いるようなクラスを提供する場合,本当に new したオブジェクトが必要なのかどうかをよく検討する.
- new が必要な場合においても,std::tr1::shared_ptr/boost::shared_ptr などのスマート・ポインタを利用して,ユーザに delete を書かせないようなインターフェースにする(理想は new 自体をユーザからは見えないようにする).
などを注意する事は必要かなと思います.