Aggiornato, vedi sotto!
Ho sentito e letto che C ++ 0x consente a un compilatore di stampare "Hello" per il seguente frammento
#include <iostream>
int main() {
while(1)
;
std::cout << "Hello" << std::endl;
}
Apparentemente ha qualcosa a che fare con i thread e le capacità di ottimizzazione. Mi sembra che questo possa sorprendere molte persone però.
Qualcuno ha una buona spiegazione del perché questo era necessario per consentire? Per riferimento, la più recente bozza C ++ 0x dice a6.5/5
Un ciclo che, al di fuori dell'istruzione for-init nel caso di un'istruzione for,
- non effettua chiamate alle funzioni I / O della libreria e
- non accede o modifica oggetti volatili e
- non esegue operazioni di sincronizzazione (1.10) o operazioni atomiche (clausola 29)
l'implementazione può essere considerata terminata. [Nota: questo ha lo scopo di consentire le trasformazioni del compilatore, come la rimozione di loop vuoti, anche quando non è possibile provare la terminazione. - nota finale]
Modificare:
Questo approfondito articolo parla del testo degli Standard
Sfortunatamente, le parole "comportamento indefinito" non vengono utilizzate. Tuttavia, ogni volta che lo standard dice "il compilatore può assumere P", è implicito che un programma che ha la proprietà non-P ha una semantica indefinita.
È corretto e al compilatore è permesso stampare "Bye" per il programma sopra?
C'è un thread ancora più penetrante qui , che riguarda un analogo cambiamento in C, iniziato dal Guy fatto l'articolo sopra riportato. Tra gli altri fatti utili, presentano una soluzione che sembra valere anche per C ++ 0x ( Aggiornamento : non funzionerà più con n3225 - vedi sotto!)
endless:
goto endless;
A un compilatore non è permesso ottimizzarlo, a quanto pare, perché non è un loop, ma un salto. Un altro ragazzo riassume la modifica proposta in C ++ 0x e C201X
Scrivendo un ciclo, il programmatore sta affermando sia che l'anello fa qualcosa con comportamento visibile (esegue I / O, accessi oggetti volatili, o sincronizzazione esegue o operazioni atomiche), o che alla fine termina. Se viola tale presupposto scrivendo un ciclo infinito senza effetti collaterali, sto mentendo al compilatore e il comportamento del mio programma è indefinito. (Se sono fortunato, il compilatore potrebbe avvertirmi al riguardo.) Il linguaggio non fornisce (non fornisce più?) Un modo per esprimere un ciclo infinito senza comportamento visibile.
Aggiornamento del 3.1.2011 con n3225: la commissione sposta il testo all'1.10 / 24 e dice
L'implementazione può presumere che qualsiasi thread alla fine eseguirà una delle seguenti operazioni:
- terminare,
- effettuare una chiamata a una funzione I / O della libreria,
- accedere o modificare un oggetto volatile, o
- eseguire un'operazione di sincronizzazione o un'operazione atomica.
Il goto
trucco non funzionerà più!
int x = 1; for(int i = 0; i < 10; ++i) do_something(&i); x++;
in for(int i = 0; i < 10; ++i) do_something(&i); int x = 2;
? O forse viceversa, con x
l'inizializzazione 2
prima del ciclo. Può dire do_something
che non importa del valore di x
, quindi è un'ottimizzazione perfettamente sicura, se do_something
non fa i
cambiare il valore in modo da finire in un ciclo infinito.
main() { start_daemon_thread(); while(1) { sleep(1000); } }
potrebbe uscire immediatamente invece di eseguire il mio demone in un thread in background?
while(1) { MyMysteriousFunction(); }
deve essere compilabile in modo indipendente senza conoscere la definizione di quella misteriosa funzione, giusto? Quindi, come possiamo determinare se effettua chiamate a qualsiasi funzione I / O della libreria? In altre parole: sicuramente quel primo proiettile potrebbe essere formulato non fa chiamate a funzioni .