web-dev-qa-db-ja.com

"std :: bad_alloc":メモリを使いすぎていませんか?

メッセージ:

terminate called after throwing an instance of 'std::bad_alloc'
what():  std::bad_alloc

私はgdbバックトレースを見ましたが、これは私が自分で実装した最低レベルのメソッドです。

/*
 * get an array of vec3s, which will be used for rendering the image
 */
vec3 *MarchingCubes::getVertexNormalArray(){
    // Used the same array size technique as getVertexArray: we want indices to match     up
    vec3 *array = new vec3[this->meshPoints.getNumFaces() * 3]; //3 vertices per face

    int j=0;
    for (unsigned int i=0; i < (this->meshPoints.getNumFaces() * 3); i++) {
        realVec normal = this->meshPoints.getNormalForVertex(i);
 //     PCReal* iter = normal.begin();

        if (normal.size() >= 3) {
            array[j++] = vec3(normal[0], normal[1], normal[2]);
        }
        cout << i << " ";
    }

    return array;
}

上記のcoutステートメントは、7000回以上の反復後に終了することを示しています。上記の関数は、アプリケーションの終わり近くで一度だけ呼び出されます。上記を呼び出す前に非常によく似た関数を呼び出しますが、問題は発生しません。

16
Rooster

私の問題は、this->meshPoints.getNormalForVertex(i)this->meshPoints.getNumFaces() * 3より短い長さの配列(またはベクトル、覚えていません)にアクセスすることでした。したがって、それは範囲外にアクセスしていました。

3
Rooster

(コメントからの移動/展開)

割り当てを解除せずに毎回新しい配列を割り当てるため、大量のメモリリークが発生します。つまり、メモリを返さずにシステムにメモリを要求し続けます。最終的にヒープ上のスペースが終了し、次の割り当てではstd::bad_alloc例外。

「Cスタイル」の解決策は、不要になったときにそのようなメモリの割り当てを解除することを覚えておくことです(delete[])ですが、これは(1)エラーが発生しやすい(たとえば、関数内に複数の戻りパスがある場合に考えます)および(2)潜在的に例外安全ではない(例外がある場合、すべての命令が潜在的な戻りパスになります!)したがって、この方法は避けてください。

慣用的なC++ソリューションは、 スマートポインター -ポインターをカプセル化し、それらが破棄されたときに関連付けられたメモリの割り当てを解除する小さなオブジェクト、またはほぼ同じであるがコピーセマンティクスを持つ標準コンテナーを使用することです。そして、いくつかのベルとホイッスル(それらの中に配列のサイズを格納することを含む)。

26
Matteo Italia

負の長さの配列を割り当てようとすると、このエラーが発生しました。

double myArray = new double [-9000];

万が一に備えて。

5
Tim Mottram