C'è una chiamata che posso fare a new
per liberare memoria come calloc
?C++: nuova chiamata che si comporta come calloc?
risposta
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.
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.
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.
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.
Non lo so; se vuole davvero spararsi al piede così male, è etico fermarlo? :-) –
Assegnare e impostare la memoria all'interno della classe. Non fare affidamento su memset. Funziona in molti casi, ma è "indefinito" nelle specifiche. –
@ McWafflestic: bello! :-) –
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.
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) –
s/opeartor/operator /;) Potrebbe essere utile mettere un avvertimento, assicurarsi di istanziare 'const zeromemory_t zeromemory;' in una singola unità di compilazione. – ephemient
@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
È 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
.
Cosa succede con le classi che in questo caso hanno definito i metodi virtuali? –
Non accade nulla di insolito: il costruttore funziona normalmente. È solo che la memoria non elaborata su cui lavora il costruttore è sempre stata cancellata. –
se non si desidera utilizzare new
, è possibile utilizzare semplicemente il vettore: vector<char> buffer; buffer.resize(newsize);
e il contenuto verrà azzerato.
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.
prova con array - non funzionerà (almeno per ISO C++ - forse alcuni compilatori con estensione potrebbero permetterlo). – Francis
class MyClass {
public:
void* operator new(size_t bytes) {
return calloc(bytes, 1);
}
}
E se possibile, puoi sostituire il nuovo operatore globale.
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.
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)
non dimenticare il # prima di definire: D (apparentemente questo sito lo rimuove. –
c'è in realtà una formattazione speciale per il codice sorgente. quattro spazi otterranno l'evidenziazione speciale (vedi la mia modifica). –
Imparo qualcosa di nuovo ogni giorno dai tuoi post! A proposito, sai perché il nuovo [N] (42) non è permesso? –
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 –
Questo è lo scenario specifico Stavo cercando, ma anche tutte queste altre risposte sono fantastiche! – nivnad