6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Constメンバ変数のあるクラスをvectorで管理する

Last updated at Posted at 2016-03-21

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使えるのでダングリングが防げるし。
これかなぁ。

6
7
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?