2016-02-14 7 views
7

(5.3.4)Un oggetto creato con il posizionamento nuovo ha una durata di archiviazione dinamica?

nuova espressione:

  • :: opt_ new new-placement_ opt nuovo-tipo-id new-initializeropt

  • :: opt_ nuovo new-placement_ opt (tipo-id) new-initializeropt

entità create da una nuova espressione hanno durata di conservazione dinamica (3.7.4). [Nota: la durata di vita di tale entità non è necessariamente limitata all'ambito in cui è stata creata. - fine nota]

Credo seguente ha 1 oggetto principale (local_object) con automatico durata di conservazione, e 3 classi vuoti con dinamico durata stoccaggio.

struct dummy 
{ 
    int a; 
}; 

char local_object[256]; 
dummy * a = new(&local_object) dummy; 
dummy * b = new(&local_object +100) dummy; 
dummy * c = new(&local_object +200) dummy; 

L'utente @ M.M. sostiene che esiste un solo oggetto (local_object) e che il resto sono solo dei puntatori. È corretto?

(3,7)

Il archiviazione dinamica durata è associato con oggetti creati con operatore nuovo

+0

'local_object',' a', 'b' e' c' hanno durata di archiviazione automatica. '* a',' * b' e '* c' no. A proposito, dovresti prenderti cura dell'allineamento quando usi il posizionamento 'nuovo'. – 5gon12eder

+0

È solo un esempio casuale tho. – Jts

+0

Qual è esattamente la tua domanda? I puntatori penzoleranno, una volta che 'local_object' esce dall'ambito ma i distruttori degli oggetti new-placement dovranno essere chiamati manualmente. O intendevi chiedere qualcos'altro? – 5gon12eder

risposta

7

Mi sembra che lo standard (come citato nel PO) può essere interpretato solo come letto, ovvero l'operatore crea oggetti di durata di archiviazione dinamica, e questo è vero anche se il la derisione della memoria è stata ottenuta per un oggetto di durata automatica.

Questo scenario preciso è previsto dalla norma in § 3.8 [basic.life] paragrafo 8, con riferimento al seguente esempio di comportamento non definito:

class T { }; 
struct B { 
    ~B(); 
}; 
void h() { 
    B b; 
    new (&b) T; 
} 

Il paragrafo recita:

Se un programma termina la vita di un oggetto di tipo T con una durata di memorizzazione statica (3.7.1), thread (3.7.2) o automatica (3.7.3) e se T ha un distruttore non banale, il programma deve garantire che un oggetto del tipo originale occupa la stessa posizione di memoria quando è implicito la chiamata al distruttore avviene; in caso contrario, il comportamento del programma non è definito.

In questo esempio, il programma ha "si è concluso il ciclo di vita" dell'oggetto b riutilizzando il suo stoccaggio, secondo quanto previsto dal comma 4 della stessa sezione: (enfasi aggiunta).

Un programma può finire la durata di qualsiasi oggetto riutilizzando stoccaggio cui l'oggetto occupa o chiamando esplicitamente il distruttore per un oggetto di un tipo di classe con un distruttore non banale.

Nel codice di esempio, distruttore b s' non è stato chiamato ma questo è accettabile perché paragrafo 4 permette esplicitamente un distruttore non banale non essere chiamato:

Per un oggetto di un tipo di classe con un distruttore non banale, il programma non è obbligato a chiamare esplicitamente il distruttore prima che la memoria che l'oggetto occupa sia riutilizzata o rilasciata;

finché il programma è pronto a convivere con le conseguenze del mancato intervento del distruttore.

Ma per tornare al paragrafo 8, il tempo di vita di è terminato e lo spazio di archiviazione è stato riutilizzato per creare un oggetto di tipo T. Questo oggetto ha durata di archiviazione dinamica, il che significa che il suo distruttore non sarà chiamato implicitamente. Come sopra, non è obbligatorio chiamare esplicitamente il distruttore, purché il programma non richieda effetti collaterali che potrebbero essere eseguiti dal distruttore.

Nonostante sia terminata la durata di b, il fatto che b abbia avuto una durata di archiviazione automatica significa che il suo distruttore verrà chiamato implicitamente quando il flusso di controllo lascia il suo ambito. Chiamare un distruttore su un oggetto la cui durata è terminata è un caso specifico del divieto di utilizzare un oggetto la cui durata è terminata, come da paragrafo 6 di § 3.8, che proibisce di chiamare una funzione membro membro non statico di un oggetto la cui durata ha terminato ma il cui archivio non è stato ancora riutilizzato o rilasciato.

Per questo motivo, il comportamento del programma di esempio non è definito.

Ma punto 7 della presente sezione fornisce un meccanismo per il programma di evitare il comportamento indefinito ricreando un oggetto diverso dello stesso tipo nella stessa posizione:

Se, dopo la durata di un oggetto ha terminato e prima che la memoria su cui è occupato l'oggetto sia riutilizzata o rilasciata, viene creato un nuovo oggetto nella posizione di memoria occupata dall'oggetto originale, un puntatore che punta all'oggetto originale, un riferimento riferito all'oggetto originale o il nome dell'oggetto originale farà automaticamente riferimento al nuovo oggetto e, una volta avviata la durata del nuovo oggetto, potrà essere utilizzato per manipolare il nuovo oggetto, se:

(7.1) - l'archiviazione per il nuovo oggetto sovrappone esattamente la posizione di memoria che l'oggetto originale occupato, e

(7,2) - il nuovo oggetto è dello stesso tipo dell'oggetto originale (ignorando il top- livello cv-qualificatori), e

(7.3) - il tipo dell'oggetto originale non è const-qualificato e, se un tipo di classe, non contiene alcun membro dati non statico il cui tipo è const-qualificato o un tipo di riferimento, e

(7.4) - l'oggetto originale era un oggetto più derivato (1.8) di tipo T e il nuovo oggetto è un oggetto di derivazione più di tipo T (ovvero non sono sottooggetti di classe base). comportamento

Quindi, nella mia interpretazione, il seguente frammento avrebbe definito:

class T { }; 
struct B { 
    ~B(); 
}; 
void h() { 
    B b; 
    new (&b) T; 
    new (&b) B; /* recreate a B so that it can be destructed */ 
} 

In breve, la norma prevede la possibilità che un oggetto di durata di conservazione dinamica può essere creato utilizzando la memoria allocata ad un oggetto della durata della memorizzazione automatica e fornisce una serie di restrizioni e requisiti per un programma ben definito che esegue questa azione, evitando così le conseguenze dell'esecuzione di un distruttore implicito su un oggetto la cui durata è stata terminata riutilizzando la sua memoria.

+0

Quindi, abbiamo 3.8 \ 4: "_il distruttore non deve essere implicitamente chiamato_" - e, 3.8 \ 8: "_quando avviene la chiamata implicita al distruttore_". Wtf? –

+0

Oh, sembra che tu debba terminare la vita di _b_ chiamando esplicitamente il suo distruttore, e non solo riutilizzando la sua memoria; altrimenti, c'è un comportamento indefinito di 3.8 \ 4, no? –

+0

@eugene: il distruttore implicito non è chiamato _on l'oggetto originale_ in virtù del fatto che il suo archivio viene riutilizzato.(Logico, perché non è facile sapere che lo spazio di archiviazione è riutilizzato.) Ma verrà chiamato il distruttore implicito, quindi è necessario che ci sia un altro oggetto in quel punto. – rici

Problemi correlati