Newsgroup: it.comp.lang.c++
Titolo: [SFOGO] Distruttore... e VS2008

Ho un Merlo che e' da stamattina sta spostando mattoni per una 
pavimentazione con quel cicalino trapanatimpani per la retromarcia.
Pure con le finestre chiuse si sente quel BIIIP... BIIIIP... BIIIIP... 
BIIIIP...
Chi mi implementa un distruttore per quel noioso cicalino?
Purtroppo non ho la classe CMerlo, ma solo la classe CLeo derivata da 
CAutista che ha un puntatore all'istanta di CMerlo che sta guidando e ho una 
classe CGugu (me stesso) che e' friend di CLeo. Ho provato a chiamare il 
metodo SpegniCicalino ma non lo compila perche' CLeo non implementa questo 
metodo. Ho provato anche a farmi passare il puntatore all'istanza di CMerlo 
ma non ho trovato nessun metodo esplicito ma soltanto un paio di 
FuseInsert/FuseRemove che dovrebbero andare bene. Non avete un amico 
elettrauto che vi dice quale ID passare alla FuseRemove per disattivare sto 
@#$%& di cicalino????????????
Domanda seria invece, ho appena installato il VS2008 e comincero' a migrare 
un progetto scritto in VS6.0 abbastanza grossino.
Ovviamente ci sono parecchie cose non standard C++ che dovro' andare a 
sistemare per far sparire un po' di errori durante la compilazione.
Avete esperienza se posso limitarmi a sistemare i vari errori e/o warning 
che verranno fuori oppure se dalla versione del C++ implementata al VS6.0 a 
quella del VS2008 c'e' effettivamente qualche vecchia pratica che e' 
assolutamente da dimenticare onde evitare errori subdoli molto gravi?
Faccio un esempio concreto: ho scoperto che facendo compilare al VS2005 un 
pezzo di codice che fa uso del post-incremento:
A = B[i++] + B[i++] + B[i++];
invece di funzionare come nel VS6.0 in qualcosa tipo:
A = B[i] + B[i+1] + B[i+2];
i+=3;
E' diventato
A = B[i] + B[i] + B[i];
i+=3;
Non ho investigato troppo su questo problema, avevo urganza di farlo 
funzionare quindi ho tolto il post-incremento.
E' qualche balla del 2005, qualche parametro non settato correttamente 
oppure mi posso aspettare che nel 2008 mi trovo cose che non funzionano piu' 
come funzionavano una volta?

 piu' come funzionavano una volta?
Se non si rispettano le regole del linguaggio, le cose possono "funzionare"
diversamente a seconda del compilatore, della versione o della situazione
atmosferica locale.
Max

 atmosferica locale.
E quindi non mi devo limitare a correggere gli errori/warning del 
compilatore, ma mi tocca andare a verificare riga per riga che non siano 
state commessi errori del genere. Questi sorgenti che devo convertire sono 
stati scritti nel corso di 10 anni da 8 persone circa (450 files sorgenti e 
10 mega di codice). Mi sa che mi aspettano lunghi mesi di test...
P.S. Per Andrea laforgia: lo so che hai ragione quando mi scrivevi che in 
programmazione bisogna imparare a costruire casi di test e non affidarsi ai 
messaggi del compilatore, ma se conosci qualche compilatore (anche non 
VS2008 a questo punto) che mi possa generare un bel po' di WARNING per dare 
una bella sgrossata a problemi simili che mi possono capitare... sarebbe 
cosa graditissima.

 cosa graditissima.
Il gcc ha le opzioni -Wall e -pedantic (ed altri flag per l'aderenza
stretta allo standard ISO) ma se il tuo codice è stato costruito per
Visual C++, devi compilarlo con quest'ultimo. Ti dico "devi" non nel
senso di obbligo, ma perché è molto poco presumibile che il tuo codice
compili anche col gcc. Di solito quando si tira su un'applicazione si
usano - benché sarebbe bene che fossero in minima parte -
caratteristiche legate al particolare compilatore. Se hai il "core"
del tuo sistema ben isolato in classi conformi allo standard puoi
provare a compilarle col gcc, come ti ho detto.

 standard puoi provare a compilarle col gcc, come ti ho detto.
Tolto una manciata di sorgenti contenenti routine matematiche di vario 
genere (alcune delle quali scritte in C), il resto e' stato abbastanza 
mischiato anche se sono state ben separati i metodi che si occupano per 
esempio dell'interfaccia utente da quelli che fanno elaborazione pura. Stavo 
valutando che mi converrebbe sdoppiare tutte le classi che contengono metodi 
specifici per l'interfaccia utente cercando di ottenere classi su due 
livelli distinti.
In questa prima fase farei dei copia & incolla, intervenendo il meno 
possibile sul codice e potrei operare sempre con VS6.0.
Nella seconda fase estirpare tutto quello che c'e' di MFC nelle classi base 
(CString, CArray tanto per citarne un paio) e reimplementarle (std:string, 
std:vector, etc.)
Quindi divertirmi con il GCC sulle classi basi per andare a caccia per 
quanto possibile di errori/orrori di vario genere e infine portare tutto su 
VS2008.
Se ci sono soluzioni piu' rapide e indolori sono ben accette.

VS2008.
Se hai un po' d'esperienza col C e col C++, gli errori/orrori li
individui abbastanza facilmente. Sicuramente esistono implementazioni
moderne di tool come il vecchio lint. Quello che posso dirti è che il
gcc, con le opzioni che ti ho suggerito, ti fa veramente le pulci.
Ora, non conosco sufficientemente bene VC++ 2008, però credo che
l'aderenza allo standard sia di molto migliorata ed è possibilissimo
che abbia diagnostiche avanzate tanto quanto quelle del gcc.

C'è una cosa del genere anche con VStudio "/Wall" oppure "/W4"
- /Wall - Enables all warnings, including those disabled by default
- /W4 - Level 4 displays all level 3 warnings plus informational warnings, 
which in most cases can be safely ignored. This option should be used only 
to provide "lint" level warnings and is not recommended as your usual 
warning level setting. For a new project, it may be best to use /W4 in all 
compilations. This will ensure the fewest possible hard-to-find code 
defects.
Tasto destro sul progetto, Properties, C/C++, General, Warning Level.
By.


 che abbia diagnostiche avanzate tanto quanto quelle del gcc.
VC e' quello che passa il convento purtroppo!
Pero'... mi pare di capire che oltre alla gestione del FW3.5 il 2008 in 
pratica e' un 2005 ripulito di bugs e aggiornato sullo standard.
Spero solo che tra due anni non esca un VC++2010 e che ci sia tutto da 
rifare!!!

 rifare!!!
Se ti atterrai allo standard ISO, questo pericolo è scongiurato.

 capitare... sarebbe cosa graditissima.
Mi sono incuriosito perché questa cosa non la sapevo... g++ (GCC) è in
grado di segnalare un warning al riguardo: vedi il seguente programma:
- ----------------
#include <iostream>
int main()
{
        int pippo[3];
        int i = 0;
        pippo[0] = 1;
        pippo[1] = 2;
        pippo[2] = 4;
        int Total = pippo[i++] + pippo[i++] + pippo[i++];
        std::cout << Total << std::endl;
        return 0;
}
- ---------------
compilandolo con 'g++ test.cpp -o test -Wall' ottieni un avviso del tipo:
- ----------------
test.cpp: In function ‘int main()’:
test.cpp:12: warning: operation on ‘i’ may be undefined
test.cpp:12: warning: operation on ‘i’ may be undefined
- ----------------
Per la cronaca, il programma stampa un valore «sbagliato» (3 invece di
7). La mia versione di g++ (GCC) è 4.1.2 20061115.
Ciao,
- -Federico
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (GNU/Linux)
Comment: Using GnuPG with SUSE - 
http://enigmail.mozdev.org
iD8DBQFIfF2aBIpu+y7DlLcRArv0AKCfpuPJN4W0fZOVACX4nQUu8rdK8wCcD63V
rN78PBGsy1CJgILRPv8e1NI=
=vqV3
-----END PGP SIGNATURE-----

> C'è una cosa del genere anche con VStudio "/Wall" oppure "/W4"
Non ho resistito e' ho provato subito: 2075 errore/i, 1219 avviso/i
I warning sono prevalentemente deprecation e unsafe.
Gli errori sono mancanze di void e lo scope delle variabili definite nei for 
e istanziate successivamente che segnala indefinite.
Ci sono pezzi scritti in C++ ma con uno stile che ricorda tantissimo il C.
Speriamo in bene! 

 grado di segnalare un warning al riguardo:
Ho provato con il VC++2008 e non segnala nessun warning (ho usato W4) ma il 
risultato e' 3.
Esattamente come mi succedeva con il VC+2005...
Mi sa che dove posso utilizzero' il GCC, se non altro per provare a 
compilare il codice e vedere cosa mi segnala lui.


Nel mio precedente progetto (c++ ovviamente) compilavamo con warning
level 4 e devo
dire che a regime è un'ottima cosa .... ti ritrovi con molti meno
errori e warning !!
in bocca al lupo :-)
by.

 in bocca al lupo :-)
grasssie! 

 
Beh, 3 è tanto "sbagliato" quanto 7.
Ad ogni modo, bisogna tenere comqunque presente che il compilatore non può
sempre diagnosticare questo tipo di violazioni. Ad esempio, questo codice
 int& func( int& i ) { return ++i; }
 A = B[ func(i) ]  + B[ func(i) ];
non produce alcun warning, ma è tanto sbagliato quanto l'altro.
Max

 non produce alcun warning, ma è tanto sbagliato quanto l'altro.
Secondo me l'esempio che hai scritto invece e' corretto.
Sarebbe sbagliato scritto in questo modo
    A = B[ func(i) ]  / B[ func(i) ];

     A = B[ func(i) ]  / B[ func(i) ];
Vedo che parlare del pericolo side-effect non è servito a niente :-)
Ha ragione Max: l'errore è nel fare affidamento sul fatto che le
operazioni vengano svolte in una sequenza precisa, quando non è così.
Non dipende dall'operazione aritmetica specifica. Se scrivi:
A = B[func(i)] + B[func(i)];
non sai quando e in che ordine, nello specifico, le due chiamate a
funzione func(i) vengono eseguite, perché non sai in che punto del
calcolo dell'espressione, il compilatore piazza il sequence point,
cioè il momento di "quiete" in cui si dedica ai "side-effect".

 cioè il momento di "quiete" in cui si dedica ai "side-effect".
Infatti, ma e' proprio quello che pensavo io per questo ho fatto parlato di 
+ e /.
Non stiamo dicendo la stessa cosa?

 Non stiamo dicendo la stessa cosa?
Temo di no.

> Quello che Max voleva sottolineare nel suo esempio č che ...
Ho capito quello che Max voleva sottolineare e non posso che essere 
daccordo!
Fatto sta che  ha scritto un codice che a tutti gli effetti funziona 
egregiamente bene su qualsiasi compilatore, nonostante sia concettualmente 
errato (per il discorso dei side-effect) e fornisce un risultato corretto! 
Era questo che volevo semplicemente dire: se invece del + mette un diviso 
allora il suo codice fornisce un risultato imprevedibile a seconda del 
compilatore adottato e quindi come esempio mi sembra nettamente piu' 
efficace.

 efficace.
*NO*. Il risultato è imprevedibile in ogni caso, anche nel caso
dell'addizione. Come già detto, non c'entra l'operazione eseguita. Ho
già ampiamente spiegato il perché nei messaggi precedenti. Se dici di
essere d'accordo, dovresti averlo capito. Forse fai bene a spiegare
che intendi tu per "codice che funziona egregiamente bene".

 dell'addizione. Come già detto, non c'entra l'operazione eseguita.
Ma scusa: in fase di esecuzione le due funzioni func(i) non restituiscono 
comunque due valori corretti?
Dato int i = 0 le due funzioni restituiscono comunque 0 e 1 oppure 1 e 0 o 
sbaglio?


None. Potrebbe. Ma potrebbe anche non farlo. Il compilator, per
esempio, è libero di individuare una chiamata alla stessa funzione
func con lo stesso parametro in due luoghi diversi della stessa
espressione e quindi limitarsi a invocare la funzione una sola volta e
usare il suo risultato in entrambi i posti. Come già ampiamente detto,
il compilatore è libero di piazzare i sequence point dove gli pare.

 point dove gli pare.
Oui, questo l'avevo capito! GIURO !

> usare il suo risultato in entrambi i posti.
Scusa ma questa cosa piu' ci penso e meno mi convince...
Ma sei proprio sicuro?
Il compilatore come puo' stabilire che le funzioni che chiamo all'interno 
della stessa espressione restituiscono lo stesso valore e quindi limitarsi 
ad invocare la funzione una sola volta?
Questo fatto mi sta sconvolgendo le poche cose che sapevo sul C++ !!!!!!!!!
Ho provato a scrivere queste due righe di codice:

 ha scritto nel messaggio 
news:487dc280$0$18150$4faf...@reader3.news.tin.it...

Mancava il codice!
int& func( int& i ) { return ++i; }
int main(int argc, char* argv[])
{
 int B[3] = {10, 20,30};
 int i = 0;
 int A = B[ func(i) ]  + B[ func(i) ];
 return 0;
}
Come risultato mi esce 50.
A me 50 sembra giusto.
Ma un altro compilatore: che risultato ti potrebbe dare?
40 o 60 ?

 A me 50 sembra giusto.
Avevo scelto appositamente un esempio del genere, proprio perché
"intuitivamente" il risultato ci sembra ovvio e difficilmente immaginiamo
che un compilatore possa produrre un risultato diverso.
Nondimeno, quel codice viola quella regola dello standard che ho citato
nella mia prima risposta in questo thread. La questione č tutta lě.
Max

 ad invocare la funzione una sola volta?
No, ripensandoci credo - riguardo questo punto specifico - d'aver
detto una cazzata e cioè il compilatore non può arrogarsi il diritto
di ridurre il numero di chiamate, perché non sa in che modo le diverse
chiamate influiranno sul flusso dell'applicazione. Ma la mia cazzata
finisce qui, perché il punto di cui si sta discutendo non è questo.
Quanto si sta dicendo nel thread e che ha ribadito Max col suo esempio
rimane valido: il suo codice viola le regole ed è sbagliato.
Il compilatore comunque potrebbe ragionare come vuole, nel trattare
quelle espressioni e quindi disattendere le aspettative di un
programmatore che immagina vi sia una sequenza di calcolo precisa.

 40 o 60 ?
Non ragionare in base all'esempio specifico, cerca di considerare
l'aspetto generale.

 nella mia prima risposta in questo thread. La questione č tutta lě.
Si, ma insisto sul fatto che nel tuo esempio la "sequence point" e' 
ininfluente proprio perche' hai usato l'operatore + e quindi non vi sono 
"side effect." E' come se per sostenere quest'altra regola dello standard 
"If an object that has automatic storage duration is not initialized 
explicitly, its value is indeterminate." io scrivessi un esempio di questo 
tipo:
void foo (int& i) {i = 0;};
int i;
foo (i);
Mi potresbbero obiettare un bel "e chi se ne frega che i non e' 
inizializzato?".
Molto meglio un:
void foo (int& i) {i++;};
dove risulta piu' evidente dove sta il problema.

 Max
Non vorrei alimentare una polemica sterile, ma perchè mi spiegate meglio 
questo sarebbe sbagliato?
Non mi sembra che violi la regola citata prima. Sbaglio?
E poi per "sbagliato" cosa intendete? UB?
GM

 chiamate influiranno sul flusso dell'applicazione.
Secondo me niente di quello che hai detto è scorretto. Se per motivi 
suoi l'ottimizzatore decide che una funzione chiamata due volte 
ritornerà sempre lo stesso valore, esso potrebbe ottimizzare il codice 
eliminando una delle due chiamate e usare una variabile intermedia.
-- 
Articolo 33 della Costituzione italiana: L'arte e la scienza sono 
libere e libero ne è l'insegnamento.
detto qesto: 
http://www.pluto.it/files/ildp/HOWTO/Coffee/Coffee.html
oppure questo? 
http://lenr-canr.org/acrobat/DeNinnoAexperiment.pdf

 eliminando una delle due chiamate e usare una variabile intermedia.
Sì, ovviamente concordo. Il problema è capire se questa deduzione da
parte del compilatore è fattibile anche nel caso postato da Max.
Quella funzione restituisce il reference ricevuto in input, dopo
averne modificato il valore, quindi il compilatore dovrebbe dedurre
che lo stato della variabile cambiare con due chiamate e che quindi
esse possono essere significative. Un po' troppo avanzato come
ragionamento ma si sa che gli ottimizzatori di oggi sono furbissimi...

 "side effect."
No GuGu, continui a sbagliarti. Non è ininfluente, dipende tutto da
come il compilatore interpreta il codice. Tu stai ragionando da umano,
secondo una linea precisa: immagini che comunque le due func(i)
vengano chiamate in sequenza e quindi, siccome l'operazione + è
commutativa, la somma dei valori restituiti è costante. Basi questo
ragionamento assumendo che all'uscita di ciascuna func() il valore di
i sia stato già incrementato e questo perché poni le tue "sequence
point" all'interno del calcolo. Il compilatore potrebbe non ragionare
così.
Ti spiego: io compilatore potrei pensare: ok, ciò che importa al
programmatore è che di ritorno vi sia il reference alla variabile e
lui (il programmatore) sa bene che *non* deve far affidamento
sull'avvenuto incremento del valore della variabile, quindi io mi
sento libero di spostare tutti i pre-incrementi a fine espressione, in
un bel sequence-point globale. Quello che accade in questo caso è che
potresti avere, in dipendenza dai compilatori, i seguenti casi:
1) B[0] + B[0] /* il compilatore ha piazzato il sequence-point *dopo*
il calcolo dell'espressione */
2) B[0] + B[1]
3) B[1] + B[0]
4) B[1] + B[1]
Visto che stiamo parlando di un'operazione aritmetica, tralascio
ovviamente il fatto che in C++ gli operatori si possono sovraccaricare
e in quel caso vattelapesca che cosa potrebbe succedere.
(Spero di non aver detto cagate)

 "side effect."
Scusa, ma secondo me la questione č molto semplice: č vero o no che
nell'espressione in questione 'i' viene modificato piů di una volta? Mi
pare di sě. Quindi la regola č violata. Fine della discussione.
Al posto di "func(i)" ci puoi mettere "++i". L'espressione viola sempre la
regola. Perň nel secondo caso GCC č in grado di diagnosticare il possibile
problema e avvertirti, nel primo caso no. Lo scopo del mio esempio era solo
questo.
Max

 parte del compilatore è fattibile anche nel caso postato da Max.
Come avete già fatto notare il codice è scorretto, quindi perché 
preoccuparsi di cosa fa il compilatore o l'ottimizzatore? E' come 
chiedersi cosa succede con:
 int a = *((int *)0);
succede che con codice simile cerchi rogne.
Max deve capire, oserei dire interiorizzare, il _perché_ quel codice 
non è valido. Se non lo capisce adesso la cosa migliore che potrebbe 
fare è: staccare il cervello, e ripensarci magari domani a mente 
fresca.


 un bel sequence-point globale. 
...
Ecco, siccome non mi avete (Andrea Laforgia e Max M.) risposto più 
sotto, intervengo quì:
secondo me state partendo dall'ipotesi (che IMHO è sbagliata) che non 
sia definito dove sono i sequence point.
Ma lo std lo definisce al punto 1.9-17 dove se capisco bene dice che ci 
sono s.p. sia in entrata sia in uscita dalle funzioni.
Quindi nell'esempio dobbiamo considerare che il fatto che i venga 
incrementato prima che la funzione ritorni è garantito.
A questo punto resta U.B. solo l'ordine di valutazione dei due operandi 
della somma ma in questo caso il risultato è definito lo stesso per via 
della commutatività (ok, se fai overload della somma e la implementi in 
modo non commutativo resta UB anche il risultato).
Tutto molto IMHO
GM

 regola.
In questo caso non c'č la chiamata a funzione e i suoi s.p. quindi hai 
ragione.
Almeno questo č quello che capisco io leggendo lo std.
GM

 sono s.p. sia in entrata sia in uscita dalle funzioni.
Non ho sottomano lo standard e quindi non posso guardare, però credo
il punto sia quello che dice Max e cioè che se in una espressione la
stessa variabile viene modificata più volte, la regola è violata.
Punto. Gli dò pienamente ragione su ciò. Secondo me non si può fare
affidamento sulla commutatività dell'operatore per il fatto che
l'unico contratto che la funzione è tenuta a rispettare col
programmatore è che sia restituito il reference alla variabile. A casa
mi guardo il punto 1.9-17 dello standard.

 preoccuparsi di cosa fa il compilatore o l'ottimizzatore?
Concordo.

 pare di sì. Quindi la regola è violata. Fine della discussione.
Sì, è questo il punto e difatti su questo sono assolutamente concorde.
Diciamo che il thread si è aperto via via in sotto-thread che non
c'entravano molto col tema principale, anche per colpa mia :-)

Andrea Laforgia ha scritto:

Nono, la regola non parla di espressione ma di sequence point:
"Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an expression.
Furthermore, the prior value shall be accessed only to determine the 
value to be stored."
E il punto 1.9-17 dice:
"When calling a function (whether or not the function is inline), there 
is a sequence point after the evaluation of all function arguments (if 
any) which takes place before execution of any expressions or statements 
in the function body. There is also a sequence point after the copying 
of a returned value and before the execution of any expressions outside 
the function. Several contexts in C++ cause evaluation of a function 
call, even though no corresponding function call syntax appears in the 
translation unit. [Example: evaluation of a new expression invokes one 
or more allocation and constructor functions; see 5.3.4. For another 
example, invocation of a conversion function (12.3.2) can arise in 
contexts in which no function call syntax appears. —end example] The 
sequence points at function-entry and function-exit (as described above) 
are features of the function calls as evaluated, whatever the syntax of 
the expression that calls the function might be."
GM

 Sì, è questo il punto e difatti su questo sono assolutamente concorde.
La regola dice:
"Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an expression.
Furthermore, the prior value shall be accessed only to determine the 
value to be stored."
La chiamata di funzione introduce un sequence point.
Nell'espressione in questione i *non* viene modificato e/o acceduto più 
di una volta tra due sequence point consecutivi, quindi la regola *non* 
viene violata.
Ciao.

 Nono, la regola non parla di espressione ma di sequence point:
Non avevo visto che avevi già risposto.
Quello che dici è corretto, l'espressione in questione non viola la 
regola, così come non la viola neppure questa (a parte che non ha alcun 
senso):
int i = 1;
if (++i && ++i)
     ;
perché anche l'operatore && introduce un sequence point.
Ciao.

 in quel caso vattelapesca che cosa potrebbe succedere.
Assolutamente corretto.

 if (++i && ++i)
Aspetta, questo è un altro caso: l'operatore && è uno dei pochi che
determina il flusso delle operazioni: cioè il primo ++i è eseguito
sicuramente prima del secondo. E' per questo che scrivere: if (a > 0
&& b/a == 1) è un'operazione sicura. Comunque ora scappo a casa,
studio e poi rispondo ;-)

 uno per ogni uscita). Quindi non c'č doppia modifica.
Sě, hai ragione. Ho detto una sciocchezza. Il fatto che ci sia di mezzo una
chiamata a funzione cambia completamente la situazione.
Max

 Quello che dici è corretto,
Avete ragione. Ho detto una sciocchezza. (Lo ribadisco anche qui, in caso
qualcuno si perda il mio messaggio nell'altro ramo.)
Max

La chiamata di funzione introduce un sequence point.
Indubbiamente.
Lo standard afferma testualmente "When calling a function (whether or
not the function is inline), there is a sequence point after the
evaluation of all function arguments (if any) which takes place before
execution of any expressions or statements in the function body. There
is also a sequence point after the copying of a returned value and
before the execution of any expressions outside the function"
E fin qui ci siamo. Vuol dire che all'atto di ciascuna delle due
chiamate a func() c'è un sequence point prima di entrare nel corpo
della funzione e c'è un sequence point una volta usciti dalla
funzione.
Il che vuole dire che, no, la regola non viene violata.
Cionondimeno, mi chiedevo se il risultato di quell'operazione non sia
ugualmente indeterminato. Mi spiego: visto che non è garantito
l'ordine di entrambe le esecuzioni della funzione func() e che l'unico
contratto che il compilatore è tenuto a rispettare è quello di dare
indietro il reference, potrebbe accadere - domando - che le due
chiamate avvengano entrambe prima della somma e che invece ai due B[]
venga passato lo stesso valore?
int i=0;
Dato A = B[func(i)] + B[func(i)];
potrebbe succedere questo? :
1) i = 0;
2) func(i): 2.1) sequence point
            2.2) esecuzione di func(); 
            2.3) sequence point: i = 1;
3) func(i): 3.1) sequence point
            3.2) esecuzione di func();
            3.3) sequence point: i = 2;
4) A = B[2] + B[2];
E' plausibile o sto dicendo una cazzata?

 preoccuparsi di cosa fa il compilatore o l'ottimizzatore? 
Ma il dubbio è, ammesso che un compilatore abbia una certa libertà nel 
decidere come valutare certe espressioni, se per una particolare 
espressione succede che qualunque modo "legale" di valutare 
l'espressione porta allo stesso risultato, allora posso confidare nel 
fatto che il compilatore mi dà QUEL risultato?
Penso che la risposta sia sì.
A questo punto resta da decidere se l'espressione
  int& func( int& i ) { return ++i; }
  A = B[ func(i) ]  + B[ func(i) ];
ha, oppure no, questa proprietà. Io ci ho pensato un po' e devo dire che 
non mi è molto chiaro. In effetti non mi è chiaro neanche quale sia 
l'effetto (se è definito) di
	++i=1;
E.

	++i=1;
Credo che questa non sia legale per il discorso dei sequence point (ma
è tardi e ho sonno...).

 incrementato prima che la funzione ritorni è garantito.
verifica comunque che ciò tenga anche per le funzioni 
espanse inline.
ciao
Soviet


 "When calling a function (whether or not the function is inline), 
ti chiedo scusa per un intervento che ho fatto senza ancora 
avere letto questo punto. Il mio dubbio sull'espansione 
inline i è rivelato ingenuo : ovviamente avevano pensato a ciò
riciao
Soviet_Mario
CUT ALL

 E' plausibile o sto dicendo una cazzata?
Direi che per quanto sopra ciò non è possibile.
Ciao.

     ++i=1;
No, non lo è perché viola la regola postata da MaxM (due assegnamenti 
alla stessa variabile all'interno di un singolo sequence point).
Da notare che neppure questa è legale:
int a = 1;
int b = ++a + a;
Perché viola la seconda parte della regola in questione.
Ciao.

 "incroci" di esecuzione.
Qundi nello standard non e' previsto un ordine di esecuzione per gli 
operatori anche se ci sono dei SP?
Dove posso reperire questo standard online per andarmelo a leggere?

 pregiudicare il senso (non il risultato) dell'espressione:
Un esempio che giudico perfetto. Il punto è tutto lì.
Se non fosse permesso all'ottimizzatore di fare questo tanto varrebbe 
eseguire il codice C++ come pcode dentro una virtual machine.


 Non sono possibili altri output.
Ok, però in questo esempio si sta usando sempre l'invocazione di
funzioni, mentre nell'altro esempio è cruciale l'accesso all'array e
quindi l'utilizzo dei valori restituiti come indici.
Nel tuo esempio, è chiaro che se non sono state invocate prima f_b e
f_c non è possibile invocare f_a (sono i suoi argomenti). Idem per f_e
e f_f rispetto a f_d, e comunque l'ordine di esecuzione tra f_a e f_d
non è definito, giustamente. Ciò non toglie che nell'esempio di Max,
il calcolo dei risultati delle due espressioni è indipendente e quindi
il compilatore potrebbe organizzare il codice come vuole (almeno
credo). Se spostasse i due calcoli *prima* del loro utilizzo come
indici dell'array, finirebbe per usare lo stesso indice per il primo e
il secondo B[]...

 Dove posso reperire questo standard online per andarmelo a leggere?
Lo standard ISO è acquistabile on-line. Non esistono versioni gratuite
AFAIK.

> Lo standard ISO è acquistabile on-line. Non esistono versioni gratuite
Perdona la mia pigrizia, mi sai dare un link dove posso acquistarlo?
Credo che tra le altre cose non sarebbe male che io e il mio collega ci 
andiamo a rileggere questo prima di tutto.

 andiamo a rileggere questo prima di tutto.
Prova a guardare qui:
http://webstore.ansi.org/FindStandards.aspx?SearchString=C%2b%2b&SearchOption=1&PageNum=0
Comunque considera che la lettura dello standard non è agevolissima.
Probabilmente trovi dei "rationale" in giro (anche a pagamento) che
spiegano meglio le questioni. Questo (che non conosco) tanto per fare
un esempio:
http://www.amazon.co.uk/ANSI-ISO-Professional-Programmers-Handbook/dp/0789720221/ref=sr_1_1?ie=UTF8&s=books&qid=1216287749&sr=8-1

 quindi l'utilizzo dei valori restituiti come indici.
Hai perfettamente ragione, chissà perché stavo pensando esclusivamente 
all'overloading del "subscription operator" (che essendo una funzione 
introdurrebbe un sequence point).
Essendo B un array l'espressione
int A = B[ func(i) ]  + B[ func(i) ];
diventerebbe
int A = *(B + func(i)) + *(B + func(i));
ed in effetti non credo questa ponga alcun vincolo al compilatore.
Ciao.

 
http://www.amazon.co.uk/ANSI-ISO-Professional-Programmers-Handbook/dp/0789720221/ref=sr_1_1?ie=UTF8&s=books&qid=1216287749&sr=8-1
Ho trovato questo:
http://www.comms.scitech.susx.ac.uk/fft/programming/ANSI-ISOCppProfessionalProgrammersHandbook.pdf
sembrerebbe proprio lui. 

sembrerebbe proprio lui. 
Già, però non ha proprio un aspetto legale :-)

 Gią, perņ non ha proprio un aspetto legale :-)
Si, l'ho lasciato perdere e ho comprato il libro (che tristezza ... si trova 
usato a 14 sterline...)