2009-04-30 8 views

risposta

70

Contrariamente a quello che alcuni stanno dicendo nelle loro risposte, è è possibile.

char * c = new char[N](); 

azzererà inizializzare tutti i personaggi (in realtà, si chiama valore di inizializzazione. Ma il valore di inizializzazione-sta per essere zero inizializzazione per tutti i suoi membri di un array di tipo scalare). Se è quello che stai cercando.

Vale la pena di notare che funziona anche per (array di) classe-tipo senza utente dichiarato costruttore, nel qual caso qualsiasi membro di loro è il valore inizializzato:

struct T { int a; }; 
T *t = new T[1](); 
assert(t[0].a == 0); 
delete[] t; 

Non è qualche estensione o qualcosa del genere. Ha funzionato e si è comportato allo stesso modo anche in C++ 98. Proprio lì si chiamava inizializzazione predefinita invece di inizializzazione del valore. L'inizializzazione zero, tuttavia, viene eseguita in entrambi i casi per gli scalari o gli array di tipi scalari o POD.

+1

Imparo qualcosa di nuovo ogni giorno dai tuoi post! A proposito, sai perché il nuovo [N] (42) non è permesso? –

+0

T() è un modulo speciale: inizializzazione del valore o (cosa era in C++ 98) l'inizializzazione predefinita T (42), tuttavia, è l'inizializzazione diretta e non funziona per gli array –

+0

Questo è lo scenario specifico Stavo cercando, ma anche tutte queste altre risposte sono fantastiche! – nivnad

2

No. Sarà sempre predefinito-inizializzare l'oggetto (i) assegnato (i), che nel caso dei primitivi non fa nulla. Dovrai seguirlo con una chiamata std :: uninitialized_fill_n o simile.

0

No. È necessario azzerare manualmente la memoria. Ricorda che lo new non riguarda solo l'allocazione della memoria, ma anche l'inizializzazione tramite i costruttori. Questo è dove calloc è utile in C (che non ha le funzioni di inizializzatore). Sei libero di scrivere un wrapper su new o anche di usare calloc, ma la maggior parte delle volte per gli oggetti non POD non ha molto senso.

5

No. Inoltre non hanno nemmeno pensare di fare qualcosa di simile:

YourClass *var = new YourClass; 
memset(var, 0, sizeof(YourClass)); 

Si potrebbe finire cestinare il tuo VTABLE (se la classe ha uno).

Si consiglia di utilizzare i costruttori per cancellare la memoria interna (variabili) della classe.

+3

Non lo so; se vuole davvero spararsi al piede così male, è etico fermarlo? :-) –

+0

Assegnare e impostare la memoria all'interno della classe. Non fare affidamento su memset. Funziona in molti casi, ma è "indefinito" nelle specifiche. –

+0

@ McWafflestic: bello! :-) –

11

No, ma è abbastanza facile creare una nuova versione che funzioni come calloc. Può essere fatto nello stesso modo in cui viene implementata la versione no-throw di new.

SomeFile.h

struct zeromemory_t{}; 
extern const zeromemory_t zeromemory; 
void* __cdcel operator new(size_t cbSize, const zeromemory_t&); 

SomeFile.cpp

const zeromemory_t zeromemory; 

void* _cdecl operator new(size_t cbSize, const zeromemory_t&) 
{ 
    void *mem = ::operator new(cbSize); 
    memset(mem,0,cbSize); 
    return mem; 
} 

Ora è possibile effettuare le seguenti operazioni per ottenere il nuovo con la memoria zero'd

MyType* pMyType = new (zeromemory) MyType(); 

Inoltre avreste bisogno fare altre cose divertenti come definire nuove [] che è abbastanza semplice.

+2

Solo per sottolineare il nome ufficiale per questo è il posizionamento nuovo. Se Danvin vuole più informazioni sull'argomento. Può anche essere usato per creare cache di oggetti (si pensi alla cache di Linux del kernel di linux) –

+2

s/opeartor/operator /;) Potrebbe essere utile mettere un avvertimento, assicurarsi di istanziare 'const zeromemory_t zeromemory;' in una singola unità di compilazione. – ephemient

+0

@ephemient, risolto l'errore ortografico. Curioso, in che modo il valore definito solo in un file .cpp può essere incluso in più di una unità di compilazione? – JaredPar

2

È possibile eseguire un sovraccarico globale dell'operatore new e prelevare la memoria non elaborata da calloc(). In questo modo la memoria viene cancellata prima che i costruttori possano funzionare, quindi non ci sono problemi lì.

Qualsiasi classe che sostituisce la nuova di per sé non otterrà il proprio calloc() -based new, ma tale classe dovrebbe inizializzarsi correttamente in ogni caso.

Non dimenticare di ignorare sia new e delete e le versioni di matrice ...

Qualcosa di simile:

#include <exception> // for std::bad_alloc 
#include <new> 
#include <stdlib.h> // for calloc() and free() 

void* operator new (size_t size) 
{ 
void *p=calloc(size, 1); 
if (p==0) // did allocation succeed? 
    throw std::bad_alloc(); 
return p; 
} 


void operator delete (void *p) 
{ 
free(p); 
} 

void* operator new[] (size_t size) 
{ 
void *p=calloc(size, 1); 
if (p==0) // did allocation succeed? 
    throw std::bad_alloc(); 
return p; 
} 

void operator delete[] (void *p) 
{ 
free(p); 
} 

Si noti che questi semplici versioni non sono del tutto esattamente quello che dovrebbe essere - l'operatore new deve eseguire un ciclo chiamando il numero new_handler (se è installato) e lanciare l'eccezione bad_alloc solo se non è presente new_handler. O qualcosa del genere, dovrò cercarlo e aggiornarlo più tardi.

Oh, e si potrebbe anche voler ignorare la versione no_throw.

+0

Cosa succede con le classi che in questo caso hanno definito i metodi virtuali? –

+1

Non accade nulla di insolito: il costruttore funziona normalmente. È solo che la memoria non elaborata su cui lavora il costruttore è sempre stata cancellata. –

0

se non si desidera utilizzare new, è possibile utilizzare semplicemente il vettore: vector<char> buffer; buffer.resize(newsize); e il contenuto verrà azzerato.

0

Sì.

int* p_scalar = new int(5);//Does not create 5 elements, but initializes to 5 

Per gli array è possibile utilizzare qualcosa come memset. Per Windows utilizzare ZeroMemory o SecureZeroMemory.

Modifica: Vedere il post di @ litb, mostra come è possibile inizializzare a 0 per gli array che utilizzano l'inizializzazione non diretta come sopra.

+0

prova con array - non funzionerà (almeno per ISO C++ - forse alcuni compilatori con estensione potrebbero permetterlo). – Francis

0
class MyClass { 
    public: 
    void* operator new(size_t bytes) { 
     return calloc(bytes, 1); 
    } 
} 

E se possibile, puoi sostituire il nuovo operatore globale.

0

si può dire:

vector <char> v(100, 0); 

che crea una serie contigua di 100 caratteri utilizzando nuovi, e li inizializza a zero. È quindi possibile accedere alla matrice con l'operatore del vettore [], o facendo:

char * p = &v[0]; 
p[3] = 42; 

Nota questo si libera anche di dover chiamare cancellare per liberare la memoria allocata.

1

Io uso un macro:

#define newclear(TYPE) new(calloc(sizeof(TYPE), 1)) TYPE(); 

per usarlo:

Whatever* myWhatever = newclear(Whatever); 

(Questo utilizza "nuova collocazione" come alcune altre soluzioni qui)

+0

non dimenticare il # prima di definire: D (apparentemente questo sito lo rimuove. –

+2

c'è in realtà una formattazione speciale per il codice sorgente. quattro spazi otterranno l'evidenziazione speciale (vedi la mia modifica). –