C ++で2次元動的配列を削除する問題(これは最終的にベクターに格納されています)
-
11-09-2019 - |
質問
だから、私は私はそれで行われていたときに解放するコンテンツこの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);
これは右、任意の問題を引き起こしているべきではないのですか?私が正しい覚えている場合は、一backは、代わりにポインタまたは参照を保存するのコピーを作成します。
PS。はい、私はベクトルを使用する必要があります。しかし、私はに許可されていないのです。
追加情報:
演算子=とコピーコンストラクタが定義されていません。私はそれが問題の原因だと思う。
解決
あなたの問題があります:
FrameData myFrame;
std::vector<FrameData> frames;
...snipped...
frames.push_back(myFrame);
ベクトルは、あなたが押し込み要素のコピーを作成します。あなたのクラスのためのあなたのコピーコンストラクタおよび/またはoperator=
のために持っていますか?あなたは何も定義されていない場合、コンパイラはあなたのために作成するデフォルトのバージョンは、単にあなたのクラスのメンバーのコピーを作成します。これは、新しいインスタンスへのポインタメンバーred
、green
とblue
をコピーします。そして、あなたはポインタを引き起こし、それがスコープの外に出る時に破壊されるコピーされた古いインスタンスを削除します。ポインタのターゲットは、このように削除されますので、あなたは、ベクター中にコピーされた一つが、その後、無効なポインタを持つことになります。
親指の良いルールは、あなたが任意の生のポインタのメンバーを持っている場合、その後、あなたはポインタが新しい値を与えられていない共有、またはされていることを確認することで、この状況を正しく処理するコピーコンストラクタとoperator=
をする必要があるということですその所有権は、インスタンス間で転送される。
例えば、std::auto_ptr
クラスは、生のポインタを有し、 - コピーコンストラクタの意味論は、ターゲットへのポインタの所有権を譲渡することである
boost::shared_ptr
クラスは、生のポインタを有している - セマンティクスは参照カウントによって所有権を共有することです。これはあなたのクラスへのポインタを含むstd::vectors
を処理するための良い方法である - 共有ポインタはあなたのための所有権を制御します。
もう一つの方法は、あなたのメンバーポインタの場所を取るためにベクトルを使用するかもしれない - メンバーのポインタはとにかく単にあなたのアレイ用の別名であるので、ベクトルは良い代替品です。
。他のヒント
私の直感では、コンパイラは一backで使用するコピーコンストラクタを生成していることです。自動的に生成されたコピーコンストラクタと代入演算子は、このインスタンスの浅いコピーになりますmemberwiseコピーを、行います。コピー中に、FrameDataの一時コピーが破壊されますと、それはそれですべてのデータを取ることは良いチャンスがあるので、残念ながら、あなたのデストラクタはコピーについて知りません。
、後の工程で再びデストラクタを呼び出すと、二重の自由になり、加えて他の割り当ては「自由」は、メモリの一部を使用している場合があります。それは、ここからのヒープ破損のための正当な理由のように見えます。
このような問題を発見するために、ベストな方法は、問題を特定するためにvalgrindのか、Purifyのようなツールを使用することが通常である。
<ストライキ>これは、あなたの質問ストライキ>への答え、ちょうど観測ではありません。
あなたのフレームデータが大きくなる可能性があるため、過度のコピーを避けるために、あなたが使用することが良いでしょうかもしれ
std::vector<FrameData *> frames;
編集: 他の人が指摘したように、これはまた、あなたのクラッシュの問題を解決します。
あなたは一backはコピーを作成することについて正しいですが、FrameDataは、適切なコピーコンストラクタと代入演算子を持っているのですか?
また、なぜここにキャストます:
delete[] ((uint8_t*) red[i]);
あなたはC-スタイルを使用(または再解釈)キャストする必要がある場合は、C ++では、コードはほぼ確実に間違っています。