0

基本的に、純粋な仮想クラス Base と、Base を継承する具象クラス Derived があります。次に、メモリの一部を割り当て、単純なキャストを介して Derived の配列として扱います。次に、= を使用して配列にデータを入力します。最後に、配列をループして、Base で宣言され、Derived で定義されている仮想メソッド GetIndex を呼び出そうとします。

問題は、Base の vtable へのポインターを読み取ろうとしてアクセス違反の例外が発生することです (Visual Studio のデバッグでは、これは __vfptr として表示され、常に 0xbaadf00d です)。

以下は、私が遭遇している問題の簡単な例です。

#include "stdafx.h"
#include "windows.h"

struct Base
{
    virtual int GetIndex() const = 0;
};

struct Derived : public Base
{
    int index;

    Derived()
    {
        static int test = 0;
        index = test++;
    }

    int GetIndex() const
    {
        return index;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    int count = 4;
    // Also fails with malloc
    Derived* pDerived = (Derived*)HeapAlloc(GetProcessHeap(), 0, sizeof(Derived) * count);

    for (int i = 0; i < count; i++)
    {
        Derived t;
        pDerived[i] = t;
    }

    // Should print 0 1 2 3
    for (int i = 0; i < count; i++)
    {
        Base& lc = pDerived[i];
        printf("%d\n", lc.GetIndex()); // FAIL!
    }
    return 0;
}

この動作は、HeapAlloc または malloc を介してメモリを割り当てる場合にのみ発生します。new[] を使用すると、正常に動作します。(また、cstor は前に 4 回呼び出されているため、出力は 4 5 6 7 です。)

4

3 に答える 3

9

なしでメモリを割り当てる場合は、配置 newとデストラクタを使用しnewてコンストラクタを手動で呼び出す必要があります。x->~Derived();

于 2010-01-11T19:55:51.633 に答える
1

C++ のデフォルト以外のアロケーターを使用する場合は、毎回コンストラクターを呼び出すことを忘れないようにするのではなく、独自の演算子 new を定義する必要があります。

void *operator new[]( size_t block_size, HANDLE heap ) {
    return HeapAlloc( heap, 0, block_size );
}

…</p>

Derived *pDerived = new( GetProcessHeap() ) Derived[ count ];

詳細は、割り当てのデフォルトの方法にするDerivedかどうか、およびパラメーターが本当に必要かどうかによって異なります。

free()取得したメモリを解放できない場合は、まだ注意が必要です。その場合、デフォルトは機能せず、を呼び出す独自の関数を作成またはdelete作成する必要があります。Derived::operator deleteobject->~Derived()

于 2010-01-11T20:23:00.843 に答える
0

最初の for ループ内では、new なしでオブジェクトを作成していると思います。これは、このオブジェクトのコンテキストが for ループであることを意味します。for ループを終了すると、この変数は存在しなくなります。

于 2010-01-11T19:55:59.980 に答える