const メンバ変数とvector問題
メイヤー氏のEffective C++にならい、
後から変更しないものはなるべくconstをつけて
イニシャライザリストで初期化するように、値が設定されるタイミングをなるべく限定してバグを生まないように心がけてプログラミングしてきたのだが。
#include <vector>
class WithConst{
public:
WithConst(const int &value):value(value){};
const int &getConstValue()const{return value;};
protected:
const int value;
};
int main(int argc, const char * argv[]) {
std::vector<WithConst> vec;
vec.push_back(WithConst(20));
vec.push_back(WithConst(30));
vec.push_back(WithConst(40));
vec.erase(vec.begin()+1);
return 0;
}
でコンパイルが通らない。
これはvec.eraseが2番目の要素を取り除いた後に3番目の要素を2番目にコピーするためにコピーアサインメントを行うためだが、コピーアサインメント・オペレータが、const int valueのために暗黙のうちに削除されているからという理由。
もちろんsetterもないクラスなので、そこまで値をガードする必要があるのかどうか分からないが、変更する「意図がない」という事をコード上に書く事は、意図の明白性、ひいてはリーダビリティのために重要なのではと思う。
なので、これが理由でconstを取るというのはイケてないという前提のもと、
もしコピーアサインメント・オペレータを自力でかくとすると以下のようになる
copy assignment の追加
class WithConst{
public:
WithConst(const int &value):value(value){};
WithConst & operator= (const WithConst & other){
if(this != &other){
int* ptr = const_cast<int*>(&this->value);
*ptr=other.value;
}
return *this;
}
const int &getConstValue()const{return value;};
protected:
const int value;
};
一応動作したが、const_castが美しくない。constメンバのあるクラスをvectorに入れるなんてみんなやりそうなことだがみんなどうしてるのだろうか...
もう一つのやり方があるとすればunque_ptrかshard_ptrをそもそもvectorに格納する方法。
shared_ptrの例
class WithConst{
public:
WithConst(const int &value):value(value){};
const int &getConstValue()const{return value;};
protected:
const int value;
};
int main(int argc, const char * argv[]) {
std::vector<std::shared_ptr<WithConst>> vec;
vec.push_back(std::make_shared<WithConst>(20));
vec.push_back(std::make_shared<WithConst>(30));
vec.push_back(std::make_shared<WithConst>(40));
vec.erase(vec.begin()+1);
std::cout << vec[1]->getConstValue() << std::endl;
return 0;
}
問題なく動作する。constnessを保持し、const_castを使わないでいいので、
こちらの方が美しい。要素をポインタで取る時もweak_ptr使えるのでダングリングが防げるし。
これかなぁ。