Newsgroup: it.comp.lang.c++
Titolo: Approfitto ancora un po della vostra bontà....

Scusate, ma ancora un post...
Se un costruttore, ad es. del tipo:
A:: A(int a,float b, double t,int d)
"preleva" come suoi parametri di ingresso il risultato dell'esecuzione di
altri membri di un altro oggetto,
cioč siano
int Classe_1:: Metodo_1(void){
              return(2);
              }
double Classe_1:: Metodo_2(void){
             return(1.65783);
             }
e istanzio, ad es.
A istanza_di_a(my_object.Metodo_1(), 3.0 ,my_object.Metodo_2(), 17);
č normale che viene prima METODICAMENTE E RIPETUTAMENTE chiamato prima il
Metodo_2()  e poi il Metodo_1() ?
Non dovrebbe essere al contrario, cioč l'ordine dei parametri nel
costruttore č anche quello di chiamata dei metodi Metodo_1 e Metodo_2?
E' forse sintomo di "un GPF"... per dirla con parole di Andrea Griffini,
cioč di un errore  " a monte" della istanziazione dell'oggetto che usa il
costruttore e crea confusione al momento in cui č il turno della chiamata a
detto costruttore  ?
Grazie in anticipo per la vostra pazienza ,
Bye,
Sebastiano

 ha scritto nel messaggio
news:8oorfj$4do$1...@nslave2.tin.it...

In una funzione i parametri vengono considerati da destra a sinistra.
Alberto

Ma allora ditelo !!!
Cavolo, non l'ho mai letto da nessuna parte.
Grazie  davvero  tanto.

Alberto
L'ordine di valutazione dei parametri di una funzione non e'
specificato e il compilatore puo' decidere liberamente come
comportarsi. E' da notare che l'ordine puo' benissimo
cambiare a seconda delle opzioni di ottimizzazione.
Il fatto che spesso la valutazione sia destra/sininstra e'
semplicemente dovuto a come i parametri devono essere
passati sullo stack ad una funzione con convenzione di
chiamata c; in altre parole spesso e' piu' conveniente
(richiede meno istruzioni assembler) eseguire una valutazione
da destra a sininstra. Non e' pero' assolutamente una cosa su
cui fare affidamento.
Se ho bisogno di un ordine di valutazione specifico e'
molto meglio (anche per chi dovra' leggere e fare manutenzione
del sorgente) scrivere il codice su linee separate
  double v1=my_object.Metodo_1();
  int v2=my_object.Metodo_2();
  A istanza_di_a(v1, 3.0 ,v2, 17);
in modo da rendere evidente che la chiamata Metodo_1 deve
per qualche ragione precedere quella di Metodo_2.
E' in particolare importante notare che l'ordine di valutazione
e' a scelta del compilatore per quasi tutti gli operatori,
incluso "<<". Considerando ad esempio
  #include <iostream>
  #include <stdio.h>
 
  char *fun(int x)
  {
    static char buf[20];
    sprintf(buf,"--%i-- ",x);
    return buf;
  }
  int main()
  {
    std::cout << fun(10) << "," << fun(20) << std::endl;
    return 0;
  }
molti compilatori scriveranno "--10-- --10--", qualcuno
scrivera' "--20-- --20--" e ovviamente nessuno scrivera'
"--10-- --20--".
Gli unici operatori che garantiscono l'ordine di valutazione
sono "&&", "||" (per la necessita' di implementare la
logica short-circuit sugli operatori nativi) e il poco
utilizzato operatore ",".
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

 "--10-- --20--".
Non mi è chiaro cosa dovrebbe dimostrare tutto questo. L'ordine di
valutazione in una concatenazione del genere non deve necessariamente
essere da sinistra verso destra? In questo modo:
( ( ( std::cout << fun(10) ) << "," ) << fun(20) ) << std::endl;
Altrimenti avremmo che l'operatore viene applicato a tipi che non sono
ostream &.
EMG

 ostream &.
Non bisogna confondere il raggruppamento con l'ordine di
valutazione. Ad esempio in
  int fun_a();
  int fun_b();
  int fun_c();
  {
    int x = (fun_a() * fun_b()) * fun_c();
  }
la prima funzione chiamata potrebbe essere benissimo fun_c().
Ordine di valutazione e priorita'/raggruppamento sono cose
indipendenti.
In alcuni casi (esplicitamente citati nella definizione del
linguaggio C++) l'ordine di valutazione e' pero' forzato.
Io per esempio ho spesso usato cose come:
  if (GetAPoint("Primo estremo della linea",&p1) &&
      GetAPoint("Secondo estremo della linea",&p2) &&
      GetColor("Colore",&c))
    Drawing.Add(new Line(p1,p2,c));
In questo caso e' garantito che la prima funzione chiamata
sara GetAPoint("Primo estremo della linea",&p1) e, solo nel
caso che questa funzione torni true la seconda funzione chiamata
sara' GetAPoint("Secondo estremo della linea",&p2) e che
solo nel caso che anche questa funzione torni true verra'
chiesto (come ultima cosa) il colore.
Andrea
--
----------------------------------------------------------------
 <\___/>  Andrea        email: agriff at tin dot it
 / . . \  "6502"          irc: _6502_@EFNET#italia
(  (")  ) Griffini   homepage: 
http://www.netservers.com/~agriff
Sent via Deja.com 
http://www.deja.com/
Before you buy.


Io sapevo che l'ordine era implementation defined.
Manlio Perillo

 valutazione.
Se intendi dire che nell'espressione scritta sopra non è dato sapere se
viene valutato prima fun(10) o fun(20) allora non lo sapevo e ne vorrei
conferma perché mi pare molto strano.
EMG



Confermo. Con l'istruzione descritta sopra il compilatore puo'
scegliere liberamente se chiamare prima fun(10) oppure fun(20).
La ragione, come gia' detto, e' che gli unici opertori che
danno una garanzia sull'ordine di valutazione sono "&&", "||"
e l'operatore ",".
Esistono ovviamente alcune garanzie implicite; come ad esempio
che al momento della chiamata di una funzione tutti i parametri
sono stati valutati (ovviamente) ma anche che tutti eventuali
effetti collaterali sono gia' avvenuti.
Questo significa che ad esempio scrivendo
    fun1(i++,j++) + fun2(33) + fun3(51)
al momento dell'esecuzione di fun1 la variabile 'i' e la variabile
'j' sono gia' state incrementate. Nota pero' che ad esempio
un ordine di valutazione valido potrebbe essere:
    chiama fun3
    incrementa j (salvando il vecchio valore)
    chiama fun2
    incrementa i (salvando il vecchio valore)
    chiama fun1
    calcola la somma dei primi due termini
    calcola la somma del risultato con il terzo termine
In alcuni casi (ad esempio se i,j sono utilizzati anche
da fun2 e fun3) questo comportamento potrebbe sorprendere.
Una regola semplice da ricordare e' che se l'ordine di
valutazione ha qualche rilevanza allora la cosa deve essere
esplicitata (regola ottima anche pensando a chi dovra' un
domani guardare e fare manutenzione del sorgente - spesso
l'autore stesso dopo qualche anno).
Fanno eccezione gli operatori "&&" e "||" che per poter
offrire l'utilissima semantica di "short circuit" offrono
garanzie maggiori. L'operatore "," in pratica e' stato
scritto con l'idea di realizzare una sequenza e quindi si
e' scelto di garantire l'ordine di valutazione; si tratta
comunque di un operatore usato molto raramente.
Purtroppo l'operatore "<<" utilizzato per l'output ha
la tendenza a sembrare una "sequenza" quando in realta'
non si tratta affatto di una sequenza. L'intera
espressione di output non offre garanzie sull'ordine
di valutazione e scrivendo:
  std::cout << fun1() << fun2() << fun3() << std::endl;
non posso sapere quale delle funzioni sara' chiamata
per prima. Ad esempio con il BCC55 il programma:
  #include <iostream>
  int fun1() { std::cout << "(fun1)"; return 1; }
  int fun2() { std::cout << "(fun2)"; return 2; }
  int fun3() { std::cout << "(fun3)"; return 3; }
  int main()
  {
    std::cout << fun1() << "," <<
                 fun2() << "," <<
                 fun3() << std::endl;
    return 0;
  }
(compilando con le opzioni di default) genera come
output
          (fun3)(fun2)(fun1)1,2,3
e questo comportamento *NON* e' un bug del compilatore.
Questa e' un'altra delle ragioni per cui la scelta
di overload dell'operatore di shift per eseguire
output non mi pare particolarmente felice.
