ポリモーフィズム利用時に非決定的なバグが混入してしまう
C++ でポリモーフィズムを利用した実装をしたいのですが、並列処理をしているわけでもないのに、プログラムを実行する度にプログラムが落ちたり落ちなかったりします。
以下のコードは、現在発生しているバグに関係していると思われる本質部分を抜き出したものです。
#include <iostream>
#include <vector>
using namespace std;
class AbstractNumber {
public:
virtual void show() = 0;
protected:
int n_;
};
class Odd : public AbstractNumber {
public:
Odd(int n) { n_ = n; }
void show() override { cout << "Odd: " << n_ << endl; }
};
class Even : public AbstractNumber {
public:
Even(int n) { n_ = n; }
void show() override { cout << "Even: " << n_ << endl; }
};
class Controller {
public:
void add(int n) {
if (n % 2 == 0) {
even_.push_back(Even(n));
numbers_.push_back(&even_.back());
} else {
odd_.push_back(Odd(n));
numbers_.push_back(&odd_.back());
}
}
void show() {
for (int i = 0; i < numbers_.size(); ++i) numbers_[i]->show();
}
private:
vector<AbstractNumber *> numbers_;
vector<Odd> odd_;
vector<Even> even_;
};
int main() {
Controller c;
for (int i = 0; i < 10; ++i) c.add(i);
c.show();
return 0;
}
Controller クラスは、Odd 型と Even 型それぞれの vector 配列、および、ポリモーフィズムを用いるための、AbstractNumber * 型の vector 配列をメンバとして持っています。
Controller クラスの add() メソッドで引数に整数を渡すと、引数の偶奇に応じて Even / Odd クラスのオブジェクトが作成され、そのオブジェクトへのポインタが numbers_ へプッシュされます。
その状態で Controller クラスの show() メソッドが呼ばれると、numbers_ が指している各オブジェクトの show() メソッドがポリモーフィズムにより適切に呼び出され、標準出力に出力される……という動作を想定して書いたものです。
しかし、このプログラムを実際に実行してみると、成功したり(0 ~ 9 まで正しく表示される)、show() で例外が発生してプログラムが落ちたりします。
また、プログラムが落ちる位置も毎回変わり、何も表示されずに落ちたり、半分ほど表示されてから落ちたりします。
以上を踏まえて質問なのですが、
- なぜ、成功したり成功しなかったりするのでしょうか。
- このバグの原因は何でしょうか。どうすれば意図通りに動作するようになるでしょうか。
以上、長くなりましたが、宜しくお願いいたします。
ここまで目を通していただきありがとうございました。
なお、Odd 型オブジェクトや Even 型オブジェクトの実体を Controller クラスに持たせるのではなく、これらのオブジェクトを Controller クラス外(たとえば main())で作成し、そのポインタを Controller クラスに持たせるような設計だと、このようなバグは発生しないことを確認しています。
ですが、処理の都合上、Odd 型オブジェクトや Even 型オブジェクトの実体も Controller クラスに持たせたいため、今回のような実装になっています。
使用環境は Wndows 10 64bit,Visual Studio 2015 Update 2 です。