#include <iostream> struct Value { int v; Value() : v(32) {} ~Value() { v = 0; } void Func() { std::cout << v << std::endl; } }; int main() { Value* p; { Value a; p = &a; p->Func(); } p->Func(); return 0; }最初のFuncの呼び出し時は、aは解体されていないので32が出力される。
二回目のFuncでは、aは解体済みなので、エラーになるか、または0が出力される。
#include <iostream> struct ISample { virtual void Func() = 0; }; struct Sample : public ISample { void Func() { std::cout << "Sample::Func" << std::endl; } }; int main() { ISample* p; { Sample s; p = &s; } p->Func(); return 0; }main関数内のブロックを抜けた時点で、sのデストラクタが呼ばれ、解体される。
Funcを呼び出した時点で、仮想関数テーブル内のデータが失われていた場合、
「純粋仮想関数がコールされた」という、初学者にとっては見慣れないエラーとなって現出する。
#include <iostream> #include <vector> struct ISample { virtual void Func() = 0; }; struct Sample : public ISample { void Func() { std::cout << "Sample::Func" << std::endl; } }; struct Object { ISample* p; Sample s; Object() : p(&s) {} }; int main() { Object o; o.p->Func(); std::vector<Object> ov; ov.push_back(Object()); ov[0].p->Func(); return 0; }最初のFuncの呼び出しは問題ない。
二回目、vectorへの要素の追加が問題。
push_back関数の実引数の部分で、まず無名ローカル変数としてObjectのインスタンスが生成される。
そして、vectorが確保している領域へ、コピーコンストラクタによってコピーされる。
ここでコピーコンストラクタが用いられることが問題。
私は、てっきり自分で定義したコンストラクタでvector内の領域が初期化されると思っていたが、
実際にはコピーコンストラクタが呼ばれるので、コピーされたpが指すアドレスは、
コピーされた先のアドレスではなく、元となった無名ローカル変数内のsのアドレスとなる。
このオブジェクトを後で使おうとすると、エラーの原因となる。
もしエラーが出ても、「純粋仮想関数がコールされた」という初学者にとっては一見意味不明なエラーとなる。
このエラーを特定するのに3日近くかかってしまった。