In ogni caso, il nuovo ritorno sarà NULL?

So che secondo lo standard C ++ nel caso in cui il nuovo non riesce ad allocare memoria, si suppone che lanci l’eccezione std :: bad_alloc. Ma ho sentito che alcuni compilatori come VC6 (o implementazione CRT?) Non aderiscono ad esso. È vero ? Lo sto chiedendo perché il controllo di NULL dopo ogni nuova istruzione rende il codice molto brutto.

VC6 non era conforms per impostazione predefinita a questo proposito. Il new VC6 ha restituito 0 (o NULL ).

Ecco l’articolo KB di Microsoft su questo problema insieme alla soluzione alternativa suggerita che utilizza un new gestore personalizzato:

  • L’operatore new non genera un’eccezione bad_alloc in caso di errore in Visual C ++

Se hai un vecchio codice scritto per il comportamento VC6, puoi ottenere lo stesso comportamento con i nuovi compilatori MSVC (qualcosa come 7.0 e successivi) collegandoti in un file object denominato nothrownew.obj . C’è in realtà un insieme piuttosto complicato di regole nei compilatori 7.0 e 7.1 (VS2002 e VS2003) per determinare se sono stati predefiniti a non lanciare o lanciare new .

Sembra che MS abbia ripulito questo problema in 8.0 (VS2005) – ora è sempre impostato su un lancio nuovo a meno che non si specifichi specificamente link a nothrownew.obj .

Nota che puoi specificare che vuoi che il new restituisca 0 invece di lanciare std::bad_alloc usando il parametro std::nothrow :

 SomeType *p = new(std::nothrow) SomeType; 

Questo sembra funzionare in VC6, quindi potrebbe essere un modo per correggere più o meno meccanicamente il codice affinché funzioni allo stesso modo con tutti i compilatori in modo da non dover rielaborare la gestione degli errori esistente.

Mi piacerebbe aggiungere l’opinione (un po ‘controversa) che il controllo di NULL dopo un tentativo di assegnazione è praticamente un esercizio di futilità. Se il tuo programma si imbatte in quella situazione, è probabile che tu non possa fare molto di più che uscire velocemente. È molto probabile che anche qualsiasi successivo tentativo di assegnazione fallisca.

Senza verificare NULL, il codice successivo tenterebbe di dereferenziare un puntatore NULL, che tende ad uscire rapidamente dal programma, con una condizione di uscita relativamente unica (e facilmente debugabile).

Non sto cercando di escluderti dal controllo di NULL, è certamente una programmazione coscienziosa. Ma non si guadagna molto da esso, a meno che non si tratti di casi specifici in cui è ansible memorizzare alcune informazioni di recupero (senza allocare più memoria) o meno memoria libera, ecc. Ma questi casi saranno relativamente rari per la maggior parte delle persone.

Detto questo, mi fiderei semplicemente che il compilatore inserisse bad_alloc, personalmente – almeno nella maggior parte dei casi.

Basato sulle specifiche del C ++, getterà sempre std :: bad_alloc quando si usa semplicemente nuovo senza parametri, ma ovviamente ci possono essere alcuni compilatori non conformi.

Non scriverei codice per essere compatibile con compilatori non c ++ compatibili. VC6 è uno di loro in questo senso.

È comunque consigliabile impostare sempre il puntatore su NULL dopo averli eliminati. Quindi, per questo motivo, è ancora necessario il controllo di NULL.

Detto questo, ecco un paio di opzioni per ripulire il tuo codice:

Opzione 1: impostazione del proprio nuovo gestore

Un modo sicuro per ripulire il codice sarebbe chiamare prima set_new_handler .

Quindi puoi controllare NULL nel gestore e lanciare std :: bad_alloc se viene restituito NULL.

Se ti piacciono le eccezioni, allora questa è la soluzione migliore. Se ti piace restituire NULL meglio, puoi farlo anche facendo una presa all’interno del tuo nuovo gestore.

Opzione 2: utilizzo di nuovo sovraccarico

Il file di intestazione standard c ++ definisce una struct nothrow che è vuota. È ansible utilizzare un object di questa struttura all’interno di una nuova per ottenere la versione sovraccaricata che restituisce sempre NULL.

 void* operator new (size_t size, const std::nothrow_t &); void* operator new[] (void *v, const std::nothrow_t &nt); 

Quindi nel tuo codice:

  char *p = new(std::nothrow) char[1024]; 

Ecco una buona refrenza per ulteriori letture