Il distruttore di un oggetto locale all'interno di un loop è garantito per essere chiamato prima della successiva iterazione?


11

Quando ho un loop e all'interno di questo loop creo una nuova variabile di stack (non allocandola sull'heap e tenendo la variabile dichiarata all'interno del corpo del loop), il distruttore di questo oggetto è garantito per essere chiamato prima dell'inizio della successiva iterazione, o potrebbe lo srotolamento del loop da parte del compilatore cambia qualcosa al riguardo?


1
Lo srotolamento del loop di per sé non cambierà l'ordine di esecuzione. Tuttavia, la parallelizzazione in loop potrebbe fare ciò.
Adrian Mole,

Risposte:


8

Da n4800:

§6.3.3 Ambito di applicazione del blocco :

Un nome dichiarato in un blocco (8.3) è locale per quel blocco; ha un ambito di blocco. La sua portata potenziale inizia nel punto di dichiarazione (6.3.2) e termina alla fine del blocco. Una variabile dichiarata nell'ambito del blocco è una variabile locale.

§10.3.6 Distruttori :

Un distruttore viene invocato implicitamente [...] quando esce il blocco in cui viene creato un oggetto (8.7)

§4.1.1 Macchina astratta :

Questa disposizione è talvolta chiamata regola "come se", poiché un'implementazione è libera di ignorare qualsiasi requisito del presente documento purché il risultato sia come se il requisito fosse stato rispettato, per quanto si può determinare dal comportamento osservabile di il programma .

[Enfasi mia]

Quindi sì. La tua variabile esce dall'ambito alla fine del loop (che è un blocco) e quindi il suo distruttore viene chiamato per quanto chiunque può osservare il comportamento del programma .


1
Non c'è niente dentro di QUANDO viene chiamato il distruttore.
rigido

2
@stark Ciò che consente loro di fare ciò è la regola as-if. Lo standard specifica solo il comportamento della macchina astratta. Non sono sicuro se è necessario entrare in tutti questi dettagli nelle risposte qui.
Max Langhof,

2
@stark Questo è, IMO, irrilevante per la domanda. Puoi anche dire che i distruttori possono essere incorporati e quindi non modificati callaffatto. Oppure, se effettivamente (come regola if) non fanno nulla, potrebbe non esserci alcun assemblaggio per tali distruttori generati.
Daniel Langr,


2
@stark Dove si definisce cosa ? Nota che questa discussione è fuori tema per la domanda. È possibile porre un'altra domanda separata su questo problema.
Daniel Langr,

8

Sì. È più facile da visualizzare se si considerano i "blocchi" in cui si dichiara una variabile, ovvero tra quale coppia di parentesi graffe. Il loop è di per sé un blocco e quando raggiunge la parentesi di chiusura, prima della successiva iterazione, vengono chiamati tutti i distruttori delle variabili di memorizzazione automatiche dichiarate nel loop.

lo srotolamento del compilatore potrebbe cambiare qualcosa al riguardo?

Come regola generale non pensare a ciò che il compilatore ottimizzerà, perché deve comunque garantire il comportamento del tuo programma, indipendentemente da ciò che fa per ottimizzarlo. In tal caso, lo srotolamento del loop non cambierà nulla in tal senso se ciò dovesse accadere.


2
+1 per la regola empirica, quando si scrive il codice non bisogna preoccuparsi degli interni del compilatore. Stava per aggiungere qualcosa con lo stesso spirito alla mia risposta, ma ora è già lì
idclev 463035818

copy-elision e RVO cambiano il comportamento del programma, no?
Jean-Baptiste Yunès,

@ Jean-BaptisteYunès Possono potenzialmente, tuttavia, lo standard consente anche a loro[class.copy.elision]
ChrisMM

Non solo un paio di parentesi graffe . Puoi scrivere for(...) X x{};e l' xoggetto sarà costruito + distrutto in ogni iterazione. Demo dal vivo . Una sezione standard pertinente è stmt.iter / 2 .
Daniel Langr,

@DanielsaysreinstateMonica Secondo §9.5.2 [stmt.iter]è puramente equivalente (sottolineatura mia): "Se il sottostate in una dichiarazione di iterazione è una singola dichiarazione e non una dichiarazione composta, è come se fosse stato riscritto per essere una dichiarazione composta contenente la dichiarazione originale ". In sostanza, con o senza le parentesi graffe per una singola istruzione significa esattamente la stessa cosa e le parentesi graffe sono implicite. L'ho omesso per chiarezza.
JBL,

2

Il distruttore è chiamato per ogni iterazione. Pertanto, in alcuni casi è più veloce dichiarare una variabile all'esterno del ciclo anziché nel ciclo. Supponendo il seguente caso:

std::string temp;
for(int i = 0; i < 10; ++i){
    temp = arr[i];
    doSomething(temp);
}

Il distruttore non viene chiamato quando viene eseguito l'utilizzo del loop. Sostituisce e basta temp.

Ma se si utilizza std::string temp = arr[i]il costruttore e viene chiamato il distruttore per ogni iterazione. Penso che questo aggiunga un po 'di runtime nel caso in cui tu abbia un loop che viene eseguito molto spesso.


notare che i distruttori chiamati o no non sono solo una questione di prestazioni. Quando si dispone di un tipo RAII, si desidera in particolare che il distruttore venga chiamato ad ogni iterazione
idclev 463035818

non sono sicuro che sia vero. Il distruttore del contenuto 'temp' contenuto nella precedente iterazione non viene chiamato proprio quando temp viene riassegnato con il nuovo valore?
user1282931

Neanche io sono sicuro al 100%. Correggi la mia risposta se hai trovato qualcosa di sbagliato. :)
Julian Schnabel il

0

Il distruttore viene chiamato prima della successiva iterazione


0

Naturalmente dtor viene chiamato alla fine dell'iterazione e lo svolgimento di loop non dovrebbe modificare questo comportamento, come qualsiasi altra ottimizzazione (un'ottimizzazione non dovrebbe modificare il comportamento del programma), tranne qualche tipo di RVO e simili che possono eliminare alcune creazioni di oggetti semanticamente spurie .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.