1

だから私はこの2D動的配列を持っています。それが終わったらコンテンツを解放したいのです。しかし、デストラクタの後でヒープの破損に遭遇し続けます。デストラクタをコメントアウトすると、コードは正常に機能します(もちろんメモリリークが発生します)。(Visual Studio 2005)

FrameData::FrameData(int width, int height)
{
    width_ = width;
    height_ = height;

    linesize[0] = linesize[1] = linesize[2] = linesize[3] = 0;

    // Initialise the 2d array
    // Note: uint8_t is used by FFMPEG (typedef unsigned char uint8_t)
    red = new uint8_t* [height];
    green = new uint8_t* [height];
    blue = new uint8_t* [height];

    for (int i=0; i < height; i++)
    {
        red[i] = new uint8_t [width];
        green[i] = new uint8_t [width];
        blue[i] = new uint8_t [width];
    }       
}

FrameData::~FrameData()
{

    // Delete each column
    for (int i=0; i < height_; i++)
    {           
        delete[] ((uint8_t*) red[i]);
        delete[] ((uint8_t*)green[i]);
        delete[] ((uint8_t*)blue[i]);       
    }

    // Final cleanup
    delete[] red;
    red = NULL;

    delete[] green;
    green = NULL;

    delete[] blue;
    blue = NULL;    
} 

コードのどこが悪いのかわかりません。唯一の別のことはどこか別の場所です、私はクラッシュが発生したループでこれを行いました

FrameData myFrame;
std::vector<FrameData> frames;
...snipped...
frames.push_back(myFrame);

これは問題を引き起こしてはいけませんよね?私の記憶が正しければ、push_backはポインタや参照を格納する代わりにコピーを作成します。

PS。はい、ベクトルを使用する必要があります。しかし、私は許可されていません。

追加情報:

operator=およびcopyコンストラクターは定義されていません。それが問題の理由だと思います。

4

4 に答える 4

5

あなたの問題はあなたがここで推測した通りです:

FrameData myFrame;
std::vector<FrameData> frames;
...snipped...
frames.push_back(myFrame);

ベクターは、プッシュした要素のコピーを作成します。コピーコンストラクターやoperator=クラス用に何がありますか?何も定義されていない場合、コンパイラーが作成するデフォルトのバージョンは、クラスのメンバーのコピーを作成するだけです。これにより、ポインタメンバーと新しいインスタンスがコピーredされます。次に、コピーした古いインスタンスは、スコープ外になると破棄され、ポインターが削除されます。ベクターにコピーしたものは、ポインターのターゲットが削除されるため、無効なポインターが含まれます。greenblue

経験則として、生のポインターメンバーがある場合は、コピーコンストラクターを作成する必要があります。operator=これにより、ポインターに新しい値が与えられ、共有されないようにするか、所有権が譲渡されるようにすることで、この状況を正しく処理できます。インスタンス間。

たとえば、std::auto_ptrクラスには生のポインターがあります。コピーコンストラクターのセマンティクスは、ポインターの所有権をターゲットに転送することです。

クラスには生のポインタがあります。boost::shared_ptrセマンティクスは、参照カウントによって所有権を共有することです。これは、std::vectorsクラスへのポインターを含むことを処理するための優れた方法です。共有ポインターが所有権を制御します。

別の方法は、メンバーポインターの代わりにベクトルを使用することです。メンバーポインターは、とにかく配列の単なるエイリアスであるため、ベクトルは適切な代替手段です。

于 2009-08-06T08:30:09.367 に答える
1

FrameDataクラスのディープコピーコンストラクターと代入演算子がない限り、私の直感では、コンパイラーはpush_backで使用するコピーコンストラクターを生成します。自動生成されたコピーコンストラクターと代入演算子はメンバーごとのコピーを実行するため、この場合は浅いコピーになります。残念ながら、デストラクタはコピーについて知らないため、コピー中に、FrameDataの一時的なコピーが破棄され、すべてのデータが一緒に取得される可能性があります。

プロセスの後半でデストラクタを再度呼び出すと、二重の空きが発生し、さらに他の割り当てが「空き」メモリの一部を使用した可能性があります。これは、ここからのヒープ破損の正当な理由のように見えます。

このような問題を見つける最良の方法は、通常、ValGrindやPurifyなどのツールを使用して問題を特定することです。

于 2009-08-06T08:35:28.607 に答える
1

これはあなたの質問に対する答えではなく、単なる観察です。

フレームデータが大きくなる可能性があるため、過度のコピーを避けるために、使用する方がよい場合があります

std::vector<FrameData *> frames;

編集:他の人が指摘しているように、これはあなたのクラッシュの問題も解決します。

于 2009-08-06T08:37:53.440 に答える
0

push_backによるコピーの作成については正しいのですが、FrameDataには適切なコピーコンストラクターと代入演算子がありますか?

また、なぜここにキャストするのですか?

delete[] ((uint8_t*) red[i]);

C ++では、Cスタイル(または再解釈)のキャストを使用する必要がある場合、コードはほぼ間違いなく間違っています。

于 2009-08-06T08:27:39.077 に答える