0

必要以上のメモリを消費しないように、2D配列を割り当てる関数があります。

_>

template <class Xvar> Xvar** New2 (unsigned int rows,unsigned int cols)
{
    Xvar**  mem;
    unsigned int size, i;

    size = rows * cols;
    mem = new Xvar* [rows];
    mem [0] = new Xvar [size];
    for (i=1;i<rows;i++)
        mem [i] = &mem [0][i*cols];
    return mem;
}

次に、そのメモリが割り当てられているかどうかを確認する必要があります。(メモリ割り当てエラーを処理します)、関数のパフォーマンスを低下させることなく。

メモリ割り当てごとにtry-catchブロックを使用するか、関数に一意のtry-catchブロックのみを使用する必要があります。

template <class Xvar> Xvar** New2 (unsigned int rows,unsigned int cols)
{
    Xvar**  mem;
    unsigned int size, i;

    size = rows * cols;
    try {
    mem = new Xvar* [rows];
    }
    catch (...) { assert (...) } 
    try {
    mem [0] = new Xvar [size];
    } catch (...) { assert (...) }
    for (i=1;i<rows;i++)
        mem [i] = &mem [0][i*cols];
    return mem;
}

または次のようなもの:

template <class Xvar> Xvar** New2 (unsigned int rows,unsigned int cols)
{
    try { 
    Xvar**  mem;
    unsigned int size, i;

    size = rows * cols;
    mem = new Xvar* [rows];
    mem [0] = new Xvar [size];
    for (i=1;i<rows;i++)
        mem [i] = &mem [0][i*cols];
    return mem;
     }catch  (...) { assert (...) }
}

最初のnewが失敗した場合、memはNULLであるため、2番目の方法はお勧めできません。したがって、mem [0]を実行すると、割り当てられていないメモリにアクセスしているため、その時点でアプリケーションが失敗します。エラーをキャッチできません。

4

2 に答える 2

4

2番目の方法では、最初の方法newが失敗した場合、評価はすぐにcatchブロックにジャンプし、にアクセスしようとさえしませんmem[0]

いずれにせよ、割り当ての失敗を許可してこれを簡単に検出したい場合は、おそらく、割り当てが失敗した場合nothrowに単に戻るバリアントを使用する必要がありNULLます。だから何かのような

mem = new (nothrow) Xvar*[rows];
if (!mem) {
    // allocation failed, do whatever you want
}
mem[0] = new (nothrow) Xvar[size];
if (!mem[0]) {
    // allocation failed, do whatever you want
}
于 2013-01-08T22:33:19.803 に答える
0

例外をまったくキャッチしないでください。関数がアンワインドされたら、RAIIを使用してメモリをクリーンアップしてください。

template <class Xvar> Xvar** New2 (unsigned int rows,unsigned int cols)
{
    unsigned int size = rows * cols;
    std::unique_ptr<Xvar*[]> mem(new Xvar* [rows]);
    mem[0] = new Xvar [size];
    for (i=1; i<rows; i++)
        mem[i] = &mem[0][i*cols];
    return mem.release();
}
  • 最初newが失敗した場合、関数は何もせず、メモリをリークしていません。std::bad_allocスローされ、それだけです。
  • 2番目が失敗した場合、unique_ptrデストラクタがそのメモリを処理するので、再び大丈夫です。
  • 次の3行はスローできないため、2番目の割り当てがリークする原因にはなりません。

GmanNickGが指摘したように、これはまだひどいコードです。それはあなたが求めたひどいコードですが、私が元のデザインを支持しているという印象を与えたくありません。私はしません。それはひどいです。

発信者が正常に取得したら、Xvar**これを破棄する唯一の方法は次のとおりです。

int **ii = New2<int>(x, y);
...
delete [] ii[0];
delete [] ii;

これはもろくて不快です。2つの優れた設計は次のとおりです。

  1. ストレージを管理し、値で返すことができる実数のmatrix/2d-arrayテンプレートクラスを使用します。その後、この値オブジェクトがスコープ外になると、メモリが再利用されます

  2. カスタム削除機能でスマートポインタを使用する

    template <typename T> struct 2dDelete
    {
        void operator() (T **rows) {
            delete [] rows[0];
            delete [] rows;
        }
    };
    
    template <typename T>
    std::unique_ptr<T*[], 2dDelete<T>> 2dNew (unsigned rows, unsigned cols)
    {
        unsigned size = rows * cols;
        std::unique_ptr<Xvar*[]> tmp(new Xvar* [rows]);
        tmp[0] = new Xvar [size];
        for (i=1; i<rows; i++)
            tmp[i] = &tmp[0][i*cols];
        // hand-over from the intermediate pointer (which only owned the
        // top-level row allocation) to the caller's pointer (which will
        // own, and clean up, the whole thing).
        return std::unique_ptr<T*[], 2dDelete<T>> arr(mem.release());
    }
    
于 2013-01-08T22:55:48.463 に答える