2012-11-29 12 views
17

Dire che ho il seguente codice in un programma C++:Che cosa significa "nuovo (e variabile) valore"? in C++ fai?

Object a = Object(someParameters); 
new (&a) Object(someOtherParameters); 

La mia ipotesi è che si sostituisce il contenuto con aObject(someOtherParameters), evitando un possibile operator= dichiarato per Object. È corretto?

+2

A parte le risposte esistenti: la sintassi nel * titolo * della tua domanda non esiste! Non è possibile utilizzare questa sintassi con qualsiasi valore, è sufficiente utilizzarlo in una chiamata del costruttore, ad esempio "valore" deve essere nella forma "T (argomenti)". –

+0

posizionamento nuovo sempre utilizzato in un pool di memoria C++ (pool di oggetti). come risposta aggiuntiva. – Healer

risposta

21

Si chiama placement new. Chiama il costruttore sulla memoria specificata anziché allocare nuova memoria. Nota che in questo caso devi chiamare esplicitamente il distruttore del tuo oggetto prima di liberare la memoria allocata.

Chiarimento. Supponiamo di aver assegnato memoria grezza

char * rawMemory = new char [sizeof (Object)]; 

e si desidera costruire un oggetto su quella memoria. Si chiama

new(rawMemory) Object(params); 

Ora, prima di liberare la memoria

delete [] rawMemory; 

si dovrà chiamare il derstuctor dell'oggetto esplicitamente

reinterpret_cast<Object*>(rawMemory)->~Object(); 

Nel vostro esempio particolare, tuttavia, il problema potenziale è che non hai distrutto correttamente l'oggetto esistente prima di costruirne uno nuovo nella sua memoria.

Bonus: mai chiesti come standard di std::vector può fare a meno dei suoi oggetti contenuti essendo default-costruibile? Il motivo è che sulla maggior parte, se non tutte, le implementazioni allocator<T> non memorizzano un T* p che richiederebbe che T sia costruttivamente predefinito in caso di p = new T[N]. Invece memorizza un puntatore char - memoria raw e alloca p = new char[N*sizeof(T)]. Quando un oggetto è push_back, chiama semplicemente il costruttore di copie con il posizionamento nuovo sull'indirizzo appropriato in tale matrice di caratteri.

+0

L'ultima frase è confusa/errata: il distruttore viene chiamato automaticamente alla fine dell'ambito prima che la memoria dell'oggetto venga liberata. Ma il distruttore per l'oggetto * precedentemente esistente * deve essere chiamato prima di sovrascriverlo. Per una maggiore bontà, questa risposta dovrebbe anche menzionare la possibilità di sovraccaricare l'operatore - potenzialmente un sovraccarico fa qualcosa di completamente diverso. –

+2

@KonradRudolph: No, non lo è. 'Class * object = new (rawMemory) Class (params);' Non è possibile chiamare in seguito 'delete object;' perché la memoria non è stata allocata dal normale 'new'. Pertanto, devi chiamare esplicitamente 'object-> ~ Class()' prima di chiamare 'delete [] rawMemory'. –

+0

L'oggetto nella domanda dell'OP è stack-allocato e del tipo corretto quindi la tua obiezione non si applica.Anche per la memoria allocata dinamicamente, puoi benissimo fare quanto segue: 'T * x = new T; X-> ~ T(); nuovo (x) T(); cancella x; '(nota l'ordine di chiamata del distruttore e posizionamento nuovo!) –

6

È noto come posizionamento nuovo: crea il nuovo Object all'indirizzo indicato all'interno delle parentesi. Il posizionamento nuovo viene in genere utilizzato per creare un oggetto nella memoria non elaborata. Costruire un nuovo oggetto sopra uno esistente, come fa questo codice, è una cattiva idea, perché non chiama il distruttore sull'oggetto originale.