前略姉さんヌルポが怖いですめんどいです不要です
ヌルポインターは怖い。いまさら言うまでもなく、怖い
だがヌルポチェックは面倒くさい。よく忘れるし、よくさぼる
だがしかし
冷静に考えてみればnewはnullを返さない
無効値ならばoptionalのように明示的に無効値を表明したほうがスマートだ
本当の本当にnullptrが必要な場面というのはそうそう多くないはずだ
だから僕は非nullなスマートポインターがほしいと思ったんだ
なおここでスマートポインターとは
- share_ptr
- unique_ptr
の2種を指す
コンストラクタはどうあるべきか
nullptrを引数にとれるコンストラクタやデフォルトコンストラクタをすべて潰し、生成にはmake_shared , make_uniqueなどを用いる
- 内部状態がnullになってはならないので当然nullptrを引数にとるコンストラクタはあるべきではない
- デフォルトコンストラクタについてはTがデフォルトコンストラクタを持っているのならば
new T()
してもよいのだが、デフォルトでnewするのはコストが大きく余計なお世話な感じがあるので潰してしまうべきだ
moveはどうするべきか
moveされたオブジェクト(つまり普段はnullになっていた右辺値のほう)はどうあるべきか
moveせずコピーする?
a=std::move(b); //a=b;と等価
shared_ptrの場合計算コストが増えてしまうが、まあ良いだろう
unique_ptrの場合そもそもコピーが使えない
フラグを保持しておき、所有権の有無を表す?
a=std::move(b); //b==(ptr=p,flag=false)
nullableな普通のスマートポインタの劣化に過ぎないし、使うか分からないフラグを持ち続けるのはなかなかにばかばかしい
気にせずnullをぶち込め!!
a=std::move(b); //b==nullptr ??
非nullポインターにnullをぶち込む非常識極まりない畜生行為。人間の所業と思えない
だがしかし、「move後のbの挙動については合法な範囲内でどのような状態になってもよい」とされている
つまり、非ヌルスマポが「この状態はnullptrだが特例的に合法」であると言い張れば何も問題ないのではなかろうか
例えば一般のunique_ptrはmove後nullptrかそれとも元の値を保持しているかは、「ご自由に」である
ご自由に、だとどうなっているのかさっぱりわからないので再代入されるまで触るべきでない
bは再代入されるまで触るべきではない値だったのだ
どうせ再代入で書き換えられるのでnullでも使う上で問題ないのでは?
しかもこの行動はもともとのスマートポインターと同じ速さで動く
結論としては
非nullptrが超限定的にnullになる可能性を受け入れれば、非nullスマートポインターが完成する。という大変後味の悪い話となった
正直move後の値を触る奴のプロダクトなんて知らん、という感じはするのだが
そのバカをやるのは締切直前の自分だったりするので
コピーコンストラクタとoperator=にassertで事前チェックを仕込むぐらいのやさしさはあってもいいかもしれない