Named コンストラクタについて考える。
ごくアタリマエのことだったりするのかもしれないのですが、
コンストラクタの引数が多くなるとわかりづらくなるので、それを避けるためにコンストラクタとは別に static でインスタンスを生成して返す関数を作るっていうのがよくありますけど、
class Human { public: // コンストラクタ、男性が true というのが // (ここではまだわかるけど引数たくさんあったりすると) // 暗号的でわかりづらい Human( bool is_male ){ } // これで作る static Human CreateMale(){ return Hoge( true ); } static Human CreateFemale(){ return Hoge( true ); } }; Human m = Human::CreateMale();
これって、コンストラクタじゃないので、生成先(ヒープ、スタック、あるいはプレースメント new)が選べなかったり、場合によって無駄にコピーコンストラクタが走ったりでなんかいや感じでした。
殆どの場合は大丈夫なんですけど、『基本ポインタアクセスして欲しくてコピーコンストラクタ殺してるけど、別にわかった上でスタックに作るのは構わないよ』とかいう型を作りたいとき、かなり困ります。(そういうときは shared_ptr 返せよ、という意見も分かるんですけど)
なので、第一引数にマーカーオブジェクトを受けるべきなんじゃないかな、って思いました。
struct MaleCreateMark {}; static MaleCreateMark create_male; struct FemaleCreateMark {}; static FemaleCreateMark create_female; class Human { public: // コンストラクタ、男性が true というのが // (ここではまだわかるけど引数たくさんあったりすると) // 暗号的でわかりづらい・・・ので、廃止する。 // Human( bool is_male ){ // // } Human( const MaleCreateMark& ){ } Human( const FemaleCreateMark& ){ } }; Human* m = new Human(create_male);
こうしておくと、あくまでコンストラクタだから無駄にコピーする必要はないし、初期化リストで効率的に初期化できるし、第一引数ならば、その後のオーバーロードで後に自由に引数追加できるっていう static の生成関数のメリットも失われないんで、いいんじゃないかな?と思った次第。