Newsgroup: it.comp.lang.c++
Titolo: Confusione con temporanei

Ciao.
Credevo che i temporanei fossero const. Invece il seguente snip compila
correttamente. E' un buco del mio compilatore o il caldo mi sta dando alla
testa?
Ciao
Alessandro Bosetti
class X
{
public:
  X (int _v = 0): v(_v) {}
  void inc() {++v;}
private:
int v;
};
X foo1()
{
  return X();
}
void foo2 (X& x)
{
  x.inc();
}
void f ()
{
  foo2 (foo1());
  foo2(X());
}

 }
Quello che sta succedendo effettivamente dipende molto dal compilatore.
Ad esempio, se supporta ancora (per quanto indebitabente) la
dichiarazione int implicita, non e' detto che distingua le due chiamate
a foo2 da due dichiarazioni.
Dopo di che in effetti in entrambe i casi non dovrebbe permetterti di
associare un valore temporaneo ad un reference non const (il parametro
di foo2).
Per il resto i valori temporanei non sono modificabili, ma vi si puo'
chiamare sopra delle funzioni membro, anche non dichiarate const. Quindi
nessuno ti vieta di scrivere direttamente
X().inc();
Ciao,
Nicola

 Credevo che i temporanei fossero const.
Credevi male.
--
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

Grazie 1000..mi sento molto meglio :)
Ciao
Alessandro Bosetti

 X().inc();
Per esempio.
Ma puoi anche chiamare una funzione membro che ritorna un reference non const e
poi ccon questo bindare una reference!
Per esempio:
class X
{
public:
  X (int _v = 0): v(_v) {}
  void inc() {++v;}
  X& operator=(int i) { v=i; return *this; }
private:
  int v;
};
X foo1()
{
  return X();
}
void foo2 (X& x)
{
  x.inc();
}
void f ()
{
  foo2 (foo1().operator=(3));
  foo2(X().operator=(2));
}
e' codice perfettamente valido.


 e' codice perfettamente valido.
Certo, perche' prima applichi un operatore al temporaneo, cosa sempre
permessa, e poi crei un'altro temporaneo, che e' il reference ritornato
dall'operatore. Poiche' il temporaneo originario e' tuttora riferito,
sopravvive, e sopravvive anche quando il tuo reference temporaneo e'
collegato al reference *non* temporaneo, ovvero al parametro di foo2.
Ciao,
Nicola

> Credevi male.
Quindi secondo te il codice che ho postato e' valido C++.
Quanto ne sei sicuro?
La risposta datami da Nicola mi e' sembrata chiara e se non l'ho fraintesa,
discordante con la tua.
La chiamata void foo2 (foo1()) dovrebbe causare un errore di compilazione,
perche' sto assegnando un valore temporaneo ad un reference non const.
Ciao
Alessandro

 collegato al reference *non* temporaneo, ovvero al parametro di foo2.
Tu dicevi che un temporaneo non e' modificabile perche' non e' un r-value. Io
dicevo che invece lo e' perche' e' un modifiable r-value.
E lo ripeto un temporaneo e' modificabile.


 perche' sto assegnando un valore temporaneo ad un reference non const.
No. Perche' stai bindando un r-value ad un refernece non const. Il fatto che ci
sia di mezzo un temporaneo e' incidentale.
Il temporaneo in se e' modificabile. Infatti e' possibilissimo creare un
temporaneo, ricavarne una reference e quindi usare questa per bindare il tuo
parametro e tramite questo modificare il temporaneo.
Se il temporaneo fosse immodificabile questo darebbe un errore o sarebbe codice
dal comportamento non definito.
Invece non solo non da errore, ma il suo comportamento e' perfettamente definito
e valido e previsto dallo standard.
Lo standard dice che un temporaneo e' un r-value e che l'algoritmo di bind di
una reference non accetta r-values a meno che la reference non sia const. Ma non
vieta di ottenere una reference non const da un temporaneo.
Lo standard prevede che un temporaneo possa essere modificato.
E su questo che Nicola non e' d'accordo.
Ma ne sono parecchio sicuro.


 E lo ripeto un temporaneo e' modificabile.
No. L'unico modo per modificare un temporaneo e', come dicevo, chiamare
un metodo non const, che e' poi quello che hai fatto tu per ottenere un
lvalue dall'rvalue.
Sempre dallo standard:
3.10:
10 An lvalue for an object is necessary in order to modify the object
   except that an rvalue of class type can also be used to modify its
   referent under certain circumstances. [Example: a member function
   called for an object (9.3) can modify the object. ]
12.1:
13 A functional notation type conversion (5.2.3) can be used to create
   new objects of its type. [Note: The syntax looks like an explicit
   call of the constructor. ] [Example: complex zz = complex(1,2.3);
   cprint( complex(7.8,1.2) ); —end example] An object created in this
   way is unnamed. [Note: 12.2 describes the lifetime of temporary
   objects. ] [Note: explicit constructor calls do not yield lvalues,
   see 3.10. ]
Ciao,
Nicola

    see 3.10. ]
Ri appunto.
Quello che non capisco e' dov'e' che secondo te dice che un temporaneo non e'
modificabile. A me sembra al contrario che 12.1-13 spieghi in che modo creare un
temporaneo e che 3.10-10 spieghi come questo sia modificabile anche se in base
alla 3.10-5 e' un r-value.
In pratica e' come se dicesse se fai cosi' (12.1-13) ottieni un temporaneo il
quale, nonostante sia un r-value (3.10-5), e' lo stesso modificabile (3.10-10).
Non e' quello che dicevo io?


Grazie anche a te per le spiegazioni
Ciao
Alessandro

 >    called for an object (9.3) can modify the object. ]
Eccezione.
Ciao,
Nicola
P.S. In soldoni: stiamo dicendo la stessa cosa, ma io la dico in modo
piu' preciso :-)

 modificabile.
Su questo concordo fino ad un certo punto...
Premetto che mi pare che lo standard parli di l-value ed r-value e non
di
temporanei (a cui ho l'impressione si riferisca parlando + in generale
di r-value, cmq non parla qui esplicitamente di temporanei).
3.10:
10 An lvalue for an object is necessary in order to modify the object
   except that an rvalue of class type can also be used to modify its
   referent under certain circumstances. [Example: a member function
   called for an object (9.3) can modify the object. ]
Si parla di "rvalue of class type", quindi in generale un temporaneo
non e` modificabile, ma lo e` in casi particolari (che poi diventano
la maggioranza
perche` alla fine lavoriamo sempre con classi, ma questo e` una cosa
diversa).
In sostanza a me pare di capire che se l'r-value (temporaneo?) e` un
tipo
non classe, non e` assolutamente modificabile in modo legale, mentre
per le
classi la cosa e` possibile tramite chiamata ad esempio di funzione
membro non
const.
Tant'e` che se non sbaglio ritornare "const T" e ritornate "T" non e`
in generale la stessa cosa, per quanto spesso non ci si preoccupi di
cio`.
Dato poi che l'uso di una funzione non const e` citata come esempio,
mi
pare che il sopracitato paragrafo non escluda l'uso di funzioni non
membro
(ma neanche le accetta esplicitamente). Purtroppo non ho modo
di vedere meglio sullo standard e di certo l'unico compilatore di cui
per ora dispongo non mi consente alcun esperimento.
Mi lascia perplesso l'uso di "shall" la dove mi aspetterei un
"must"...
Paolo
--
Paolo Marotta
Home: 
http://web.tiscalinet.it/paolo_marotta
Master's Level in C++ Certified by Brainbench
http://www.brainbench.com/transcript.jsp?pid=2440649

 "must"...
In testi a carattere normativo "shall" introduce una norma obbligatoria.
Ciao,
Nicola

 piu' preciso :-)
Infatti l'unica cosa che ti contesto e' la frase "un temporaneo non e'
modificabile" che secondo me hai dedotto incorrettamente dallo standard.


 "must"...
E' la stessa cosa. La differenza e' poco percepibile per noi italiani. In
inglese puro (storico, non il moderno colloquiale) il "dovere" e' espresso quasi
sempre con shall. Il termine must e' riservato a quando il concetto di dovere e'
assolutamente imprescindibile.


"must"...
Non devi leggere "shall" come "should". In quella forma e'
un imperativo... un po' come nella Bibbia quando leggi
"tu farai questo", "tu non dirai quello".
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

 reference costante e poi usare un cast per rimuovere il const.
Questo fa parte degli "sporchi trucchi"... i cast sono comunque sempre
potenzialmente pericolosi e ricadono su quelle cose per cui "tu
programmatore sai quello che stai facendo, io compilatore
semplicemente eseguo".
Tutte le operazioni di cast sono in linea di principio una violazione
del type system (per quanto si possa essere sicuri che non ci siano
problemi).
