Elimina array 2D C ++

Questi due metodi per liberare un array 2D sono simili?

int** M = new int*[5]; for (int i = 0; i < 5; ++i) M[i] = new int[3]; for (int i = 0; i < 5; ++i) { for (int j = 0; j < 3; ++j) { M[i][j] = i + j; } } 

cancella I:

 for (int i = 0; i < 5; ++i) delete [] M[i]; delete [] M; 

ed elimina II:

 delete [] *M; delete [] M; 

Questi due codici sono equivalenti?

delete [] *M; è lo stesso di delete [] M[0] , quindi non equivale a cancellare tutto M[i] in un ciclo perché solo il primo verrebbe cancellato. Il ciclo è il modo corretto per evitare perdite di memoria.

O meglio, usa std::vector invece di allocazioni manuali e non dovrai preoccuparti di eliminare i puntatori.

Non sono simili. L’ovvio motivo per cui non sono simili è che stai chiamando new[] 6 volte, e nella seconda versione di delete[] , stai chiamando “delete” 2 volte.

 delete [] *M; delete [] M; 

Per ogni chiamata a new[] , devi abbinarla a delete[] , e ovviamente non lo stai facendo.

Se si desidera che le due chiamate da delete[] corrispondano, è necessario modificare il modo in cui è stato assegnato l’array 2d. Il cambiamento sarebbe questo:

 int** M = new int*[5]; int *pool = new int[5*3]; for (int i = 0; i < 5; ++i, pool += 3) M[i] = pool; 

Nell'esempio sopra, vengono effettuate solo 2 chiamate a new[] , una volta per i puntatori di riga e una seconda per il pool di memoria. Quindi il ciclo punta semplicemente ogni puntatore di riga all'interno del pool nel punto corretto.

Ora, la "2 chiamata" delete[] funzionerà correttamente, a patto di non fare nulla di strano come la memoria corrotta tra il tempo assegnato e trasferito l'array.

Il vantaggio di allocare array 2d in questo modo è che new[] viene chiamato solo due volte, indipendentemente dal numero di colonne. Quindi, se avessi una matrice di 10.000 x 10.000, la tua versione originale dovrebbe chiamare new[] 10.001 volte, mentre la versione precedente che utilizza il pool avrebbe bisogno solo di 2 chiamate a new[] . Questo probabilmente velocizzerebbe il programma, poiché l'allocatore viene chiamato solo due volte (e poi due volte di più per deallocation).

Inoltre, il metodo sopra è preferito se i dati dell'array devono essere contigui, in modo tale che l'aritmetica del puntatore possa essere usata per andare a qualsiasi riga o colonna.

Tuttavia, assicurati che:

  • il tuo array non cambia dimensione e
  • non è irregolare (tutte le righe devono avere lo stesso numero di colonne).

Altrimenti diventa più difficile mantenere una matrice assegnata nel modo in cui ho descritto.