そこにあるC++の達人が、この奇妙な状況に光を当てることができるのではないかと思います。Box2D物理エンジンに付属する例の1つは、「純粋仮想メソッドが呼び出されました」というメッセージでクラッシュしますが、特定のコンパイラーでのみ(リリースビルドでのみ)クラッシュします。
ご存知かもしれませんが、Box2Dはかなり堅実なコードの塊なので、特にこの特定のコンパイラでのみ発生することを考えると、これはコンパイラの問題である可能性があると思います。私はWindows7でmingw32を使用しています:
> gcc.exe --version
gcc version 4.4.0 (GCC)
以下は、Box2Dの関連部分の抜粋です。完全なソースは次の場所で確認できます。
b2Shape.h
b2CircleShape.h
b2CircleShape.cpp
SensorTest.h
//base class
class b2Shape
{
public:
virtual ~b2Shape() {}
virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0;
};
//sub class
class b2CircleShape : public b2Shape
{
public:
b2CircleShape();
b2Shape* Clone(b2BlockAllocator* allocator) const;
};
inline b2CircleShape::b2CircleShape() {}
b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const
{
void* mem = allocator->Allocate(sizeof(b2CircleShape));
b2CircleShape* clone = new (mem) b2CircleShape;
*clone = *this;
return clone;
}
クローン機能の新しい配置に注意してください。
ここで、問題の原因となる実行は次のように要約されます。
{
b2CircleShape shape;
shape.Clone(allocator); //ok
}
{
b2CircleShape shape;
shape.Clone(allocator); //"pure virtual method called"
}
そもそも仮想メソッドを呼び出す方法を学んだ後、基本クラスのコンストラクターで仮想関数を呼び出すという古典的なケースに適合しないため、ここで仮想メソッドが呼び出される理由を理解しようとしました。盲目的につまずいた長いセッションの後、私は上記の最小限のケースを思いついた。
私の大げさな推測では、コンパイラはこれら2つのb2CircleShapeインスタンスが同じスコープで使用されていないことを確認できるほど賢いので、1つにスペースを割り当てて再利用するだけです。最初のインスタンスが破棄された後、vtableは期待どおりにホース接続されます。次に、何らかの理由で2番目のインスタンスが構築されたときに、vtableが再度構築されません...?
この問題を回避するために2つのことを思いつきましたが、私が言ったように、コンパイラの問題のように思われるので、このコードを変更する必要があることを示唆していません。
疑わしい修正番号1は、基本クラスの仮想デストラクタ定義をコメントアウトすることです。私がこの主題に関して読んだすべての情報は、これが答えではないことを示唆しています。(興味深いことに、基本クラスのデストラクタから'virtual'修飾子を削除するだけでは不十分であることがわかりました。コンパイラは、何も指定されていない場合、デフォルトのデストラクタ〜b2Shape(){}を提供するので、結果が異なるのはなぜですか。とにかくデフォルトが実際に何であるかを指定した場合、まあ、これは本当に重要なことではありません...)
私が発見したそれほど疑わしくない修正番号2は、サブクラスコンストラクターから「インライン」を削除することでした。おそらく、新しいインライン構造と再利用されたインスタンスを同じスタックフレームに配置することについて、うまく連携できないことがあります。(更新:さらにチェックすると、新しい配置は無関係であることが示されます)
さらにいくつかの調査によると、コンパイラーは「インライン」の提案に関して好きなことを自由に行うことができます。したがって、他のコンパイラーは「インライン」を無視しているため、この問題は発生しないのではないでしょうか。