#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日近くかかってしまった。
0 件のコメント:
コメントを投稿