Newsgroup: it.comp.lang.c++
Titolo: Comportamento anomalo di egcs

Salve
Ho riscontrato un comportamento anomalo nel compilatore c++ GNU.
Non so a cosa attribuirlo esattamente, ho qui un sorgente di prova con
--- pippo.cpp --- begin
#include <iostream.h>
class Pippo
{
   int a, b;
public:
    Pippo() : a(0), b(0) {}
    Pippo(int a, int b) : a(a),b(b) {}
    ~Pippo() {}
    Pippo & operator =(const Pippo &p) { a = p.a; b = p.b; return *this; }
    void set(int x, int y) { a=x; b=y; }
    Print() { cout << "a = " << a << " b = " << b << endl; }
};
class Pluto
{  
   int   num;
   Pippo array[10];   
public:
   Pluto( int n, Pippo *p ) : num(0)
   { while(num < n) array[num] = p[num++]; }
   ~Pluto() {}
   Print() { int i=0; while(i<num) array[i++].Print(); }
};
main(int argc, char **argv)
{
   Pippo pippo[10];
   int i;
   cout << "Preparo un po' di Pippo" << endl;
   for (i=0; i<7; i++)
   {
      pippo[i].set(i+1,i*2);
      pippo[i].Print();
   }
   cout << "Adesso creo Pluto" << endl;
   Pluto pluto(i,&pippo[0]);
   pluto.Print(); 
}
--- pippo.cpp --- end
l'output e' il seguente:
Preparo un po' di Pippo
a = 1 b = 0
a = 2 b = 2
a = 3 b = 4
a = 4 b = 6
a = 5 b = 8
a = 6 b = 10
a = 7 b = 12
Adesso creo Pluto
a = 0 b = 0
a = 1 b = 0
a = 2 b = 2
a = 3 b = 4
a = 4 b = 6
a = 5 b = 8
a = 6 b = 10  
Il costruttore della classe Pluto si comporta in maniera strana,
credo a causa dell postincremento di num dentro 
{ while(num < n) array[num] = p[num++]; }
se sostituisco questa riga con 
{ for(num=0; num<n; num++) array[num]=p[num]; }
funziona tutto.
A prima vista sembra che il lato destro dell' assegnamento venga
valutato prima di quello sinistro, come se l'istruzione fosse :
while(num<n) { t = p[num++] ; array[num] = t; }
la cosa strana e' che se invece di un array di oggetti 
ho un array di char la copia avviene correttamente.
Ho riscontrato questa anomalia con egcs-1.0.2 su Linux
Avete qualche spiegazione ?
Forse lo standard non garantisce un ordine nella valutazione dei due operandi ?
Fabio

 Forse lo standard non garantisce un ordine nella valutazione dei due operandi ?
Mi sembra (ma non ne sono sicuro) che, nel caso di assegnazioni, sia
garantita la valutazione da destra verso sinistra (altrimenti non
funzionerebbero le assegnazioni concatenate, o no?).
EMG

Forse lo standard non garantisce un ordine nella valutazione dei due operandi ?
Prima l'operando di destra e poi quello di sinistra!
Paolo
----------------------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
----------------------------------------------------------

 Paolo
Fabio

 dei membri, tu riesca comunque ad accedervi....
Per l'espressione nella parentesi si usano le normali regole,
quindi a e b si riferiscono ai paramentri del costruttore.
Invece per le variabili fuori dalle parentesi il compilatore
va a cercare solo fra i membri della classe, quindi a e b
si riferiscono ai membri, anche se normalmente sarebbero
nascosti dai paramentri.
	Mauro

 avviene anche con Turbo C++ e DJCPP)
[Sicuro al 95%]
Il compilatore e' libero di eseguire l'incremento sia prima che
dopo l'assegnamento. L'unica cosa che deve garantire e' che il
num usato per accedere a "p" e' quello vecchio, prima dell'incremento,
e che, alla fine di tutto, num e' stato incrementato.
E' lo stesso problema di espressioni come  func( i++, i++ )
dove non si puo' sapere esattamente con che paramentri verra'
chiamata la funzione.
Il fatto che i risultati siano diversi a seconda dei tipi usati
probabilmente dipende dal fatto che lavorando solo con tipi 
standard, il compilatore ottimizza tutto e mette l'incremento
dove gli fa piu' comodo, mentre con tipi/operatori user-defined
si sbilancia meno.
	Mauro

Probabilmente c'e' qualcosa che non va nella mia definizione dell'operatore.
Ancora piu` strano (o sono io che sono andato fuori di testa o ci sono molte cose
che non tornano), la tua definizione di Pippo& operator= e` corretta 
(al piu` la modificherei in const Pippo& operator=...)
e oltretutto non vedo il motivo per cui dovrebbe generare un temporaneo.
Ancora piu` strano il fatto se si pensa che l'operatore di default farebbe esattamente le
stesse cose.
Ci sarebbero altre due cose anomale nel tuo codice che comunque non dovrebbero
influire sul problema:
1) Pippo::Print va dichiarata void, perche` il default sui compilatori standard e` int
2) main ha il seguente prototipo:
       int main(int, char* []);
Ad ogni modo per risolvere il problema, evita istruzioni con side effect piu` o meno nascosti,
nel caso sposta l'incremento di num, fuori dall'assegnamento all'array (oltretutto guadagni
in leggibilita`).


si sbilancia meno.
Questo e` un altro discorso...
In ogni caso, l'indice dell'lvalue sarebbe legato al valore assunto dall'indice
dell'rvalue dopo l'applicazione di operator++(int) perche` in un assegnamento
l'rvalue viene totalmente valutato prima dell'lvalue.


 t[6] = a[5];
Dallo standard, versione nov. 96 (quella definitiva non dovrebbe
essere cambiata, almeno in questa parte, se qualcuno c'e' l'ha
potrebbe dare conferme o smentite):
Par. 5.4 (Expressions)
  Except where noted, the order of evaluation of operands of  individual
  operators  and subexpressions of individual expressions, and the order
  in which side effects take place, is unspecified.
Poi porta come esempi (che non sono regole, ma non penso che mettano
esempi sbagliati):
          i = v[i++];      // the behavior is undefined
          i = 7, i++, i++; // `i' becomes 9
          i = ++i + 1;     // the behavior is undefined
          i = i + 1;       // the value of 'i' is incremented
Dal primo esempio (simile al nostro caso), si vede che i potrebbe
essere incrementato anche dopo l'assegnamento.
	Mauro