私はいくつかの一般的なタイプのコンテナを「ラップする」ために使用しているクラステンプレートを持っています。現在、このようになります私はプレースメントの新しい&仮想関数を使用しています。なぜ私の仮想関数テーブルが間違っていますか?
getItems(Cont<ItemType> x);
削ぎ落とした実装では、(私はベクトルのコードのみが含まれます):目標は、次のようになり、単一の機能を
getItems(vector<ItemType> &x);
getItems(set<ItemType> &x);
getItems(my_custom_vector<ItemType> &x);
(...and several others...)
を交換することである
template< class T > ContBase {
public:
ContBase(void *container) : mContainer(container) {}
virtual void add(const T& item) = 0;
virtual void clear() = 0;
protected:
void *mContainer;
};
template< class T > ContVector : public ContBase<T> {
public:
ContVector(std::vector<T> &native_container)
: ContBase((void *) &native_container) {}
void add(const T& item) { vec().push_back(item); }
void clear() { vec().clear(); }
protected:
std::vector<T> &vec() { return *(std::vector<T> *) mContainer; }
};
template< class T > class Cont {
public:
Cont(std::vector<T> &x) { new (&mMem) ContVector<T>(x); }
void clear() { container()->clear(); }
void add(const T& item) { container()->add(item); }
protected:
ContBase<T> *container() { return (ContBase<T> *) &mMem[ 0 ]; }
unsigned char mMem[ sizeof(ContBase<T>) ];
};
私はいくつかの初期テストを行いました。制御されたベンチマークセットアップでうまくいきました。ここの主な難題は、の賢明なのContのコンストラクタでのその配置の使用です。しかし、いったん実際のアプリケーション(Visual Studio 2010 C++コンパイラ)にスタックして全体プログラムの最適化(リンクタイムコード生成、速度最適化など)を実行すると、重大な問題が発生し始めました。
VFPTR: 0AD98708
// Repeat above line 17 times
VFPTR: 0018B830
:私は、この(非常識な型キャストは、VC++での仮想関数テーブルの値を取得するためのハックであることに注意してください)のような出力を提供します
void MyClass::myFunc(Index x, Cont<Index> container, uint r)
{
// ... Return if x is invalid
cerr << "VFPTR: " << (void*) ((uint *) ((void*) &verts))[0] << endl;
container.add(x);
// ...Potentially add some more things to container.
}
:具体的には、私はこのような機能を持っています
まず、仮想関数ポインタはと異なる可能性があります。第2に、この同じコードがデバッグモードで動作するのは面倒です。最適化がオンになっている場合にのみ表示されます。第3に、新しいポインタ(0018B830)がベースクラスの仮想関数テーブルへのポインタであることは注目に値する。ContBase。クラッシュは、NULL値であるcontainer.add(x)を呼び出すと発生します。
私の中核的な質問は、ここにあります:この法的コードですか、または私は未定義の行動事例を見逃しましたか?マイクロソフトのコンパイラはここで壊れていますか、または私のコードは未定義ですか?
プレースメントのnew、 'void *'などを使って大規模に複雑化していると思うのですが、 'getItems'関数を引数に対してパラメータ化したテンプレートにするのはなぜですか? – templatetypedef
オフトピックですが、重要だと思います。 'unsigned char mMem [sizeof(ContBase < T >)];'は、 'ContBase < T >'に対して正しく整列されません。 –
'ContBase <>'はコンストラクタに渡された 'std :: vector <> 'に_pointer_を格納します。 'MyClass :: myFunc'が実行されている時点で' std :: vector <> 'がまだ生きていることを確かめますか?それが削除されたり範囲外になったりすると、単純なオブジェクトライフタイム関連のUBがここにあります。 (あなたがBoost.Variantの観点から 'ContBase <>'を実装した場合、あなたの実装は**大幅に**簡素化されます(http://www.boost。 – ildjarn