ポリモーフィズム利用時に非決定的なバグが混入してしまう
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 です。