std::vectorでハマった。

今日はC++で作業していたのですが、std::vectorでハマりました。

最初、次のようなコードを書いていました。(イメージです)

struct SomeStruct {
  int number;
  float array[2];
};

void function(std::vector<SomeStruct> &struct_list) {
  for (int i = 0; i < N; i++) {
    SomeStruct some_struct; // SomeStructを作って
    some_struct.number = i; // 値をいろいろ入れて
    some_struct.array[0] = (float)i / N;
    some_struct.array[1] = (float)N / (i + 1);
    struct_list.push_back(some_struct); // vectorに入れる
  }
}

しかし、これではstruct_listの内容がどうもおかしいということに気付きました。
なんというか、SomeStruct::arrayの中身が激しく壊れています。

なんだこれ、としばらく考えたあと、ちょっと検証を行って分かった事実が
SomeStructデストラクタが呼ばれているということでした。

よくよく考えてみればそれは当たり前で、ループ内のsome_structの寿命はループブロックの終わりまでです。
デストラクタが呼ばれるのも当然です。

当たり前のことでも、JavaとかC#とかの「基本的に参照で確保して、GCで回収」な言語を使っているとウッカリ忘れがちですね。

注意したいなと思った日でした。

あ、今回どのように修正したかというと、このように修正しました。
たぶんもっとスマートな方法があると思いますので、もしご存知でしたら教えていただけると幸いです。
(それこそスマートポインタの出番でしょうか?)

// ポインタを渡すようにした
// 解放は呼び出し側が責任をもって行う必要がある
void function(std::vector<SomeStruct*> &struct_list) {
  for (int i = 0; i < N; i++) {
    SomeStruct *some_struct = new SomeStruct();
    some_struct->number = i;
    some_struct->array[0] = (float)i / N;
    some_struct->array[1] = (float)N / (i + 1);
    struct_list.push_back(some_struct);
  }
}