Newsgroup: it.comp.lang.c++
Titolo: const / non-const

class A
{
public:
   void f() {}
};
A g() { return A(); }
void h(A& a) {}
int main()
{
   h(g());	// ???
   g().f();	// ???
}
Perché si compila?
Pensavo che gli oggetti temporanei fossero const.
Kiuhnm

 ha scritto nel messaggio 
news:440a0ff4$0$18285$4faf...@reader1.news.tin.it...

GCC 4.01 mi dą questo errore:
CONST.cc: In function 'int main()':
CONST.cc:12: error: invalid initialization of non-const reference of type 'A&' 
from a temporary of type 'A'
CONST.cc:8: error: in passing argument 1 of 'void h(A&)'
mentre sia BCC55 che VCToolkit2003 mi danno praticamente lo stesso messaggio 
ma come warning.
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg
The EMG Music page:         
http://www.emagsoftware.it/emgmusic
 

 }
Questo deve compilare. I temporanei non sono const.
Max

 Questo deve compilare. I temporanei non sono const.
Veramente ho letto ovunque che i temporanei /sono/ const.
Non ha senso che il primo caso sia vietato mentre il secondo no.
Kiuhnm

Kiuhnm wrote:

Non mi risulta. Dove l'hai letto?
Se fosse stato scritto:
   const A g() { return A(); }
allora il valore ritornato da "g" sarebbe stato costante, e la 
compilazione avrebbe segnalato errore ad entrambe le righe di "main".
Il programma citato, se compilato con VC++ 7.1 senza opzioni, compila 
senza errori, ma se si usa l'opzione /Za (Disattiva le estensioni) 
emette il seguente errore:
ref.cpp(12) : error C2664: "h": impossibile convertire il parametro 1 da 
"A" a "A &"
         Impossibile associare un riferimento non "const" a un elemento 
non lvalue
Mentre con l'opzione /W4 (Imposta il livello di avviso a 4) emette gli 
avvisi:
ref.cpp(8) : warning C4100: "a": parametro formale senza riferimenti
ref.cpp(12) : warning C4239: utilizzata estensione non standard: 
"argomento". Conversione da "A" a "A &"
         Impossibile associare un riferimento non "const" a un elemento 
non lvalue
Da come si vede, si puo' sempre inizializzare una variabile riferimento 
con un oggetto non temporaneo o con un oggetto temporaneo costante, ma 
l'inizializzazione con un oggetto temporaneo non costante e' vietato 
dallo standard, ma ammesso come estensione dal compilatore Microsoft.
Se vuoi essere conforme allo standard, usa sempre l'opzione /Za (oppure 
l'opzione /W4 o l'opzione /Wall, che attiva tutti gli avvisi).
-- 
     Carlo Milanesi
 
http://digilander.libero.it/carlmila

 l'opzione /W4 o l'opzione /Wall, che attiva tutti gli avvisi).
Ok.
Kiuhnm

 corrected by the ISO/ANSI C++ standards committee;[..]".
Qui non e' chiaro a quale aspetto del linguaggio e a quale versione
dello standard si riferisce Murray.
Non ho letto lo standard, ma mi sembra che, almeno per molti 
compilatori, gli oggetti temporanei di tipo classe, se non specificati 
"const" non sono const.
Quindi la seguente riga e' sempre corretta:
    std::complex<double> a, b; a + b = 7;
Invece gli oggetti temporanei di un tipo fondamentale sono sempre const,
quindi la seguente riga e' illegale:
    int a = 0, b = 0; a + b = 7;
In effetti questa differenza tra i tipi definiti dall'utente e i tipi 
predefiniti sembra illogica anche a me, come forse a Murray, anche 
perche' l'uso di oggetti temporanei non const e' spesso indice di errore 
logico (bug) e comunque l'esigenza e' sempre aggirabile con un paio di 
righe di codice in piu'.
Per esempio, la seguente riga e' corretta.
     ofstream("temp.dat").write("XYZ", 3);
Questa breve istruzione apre il file "temp.dat" in scrittura testuale, 
ci scrive dentro tre caratteri e chiude il file.
Se gli oggetti temporanei fossero const, non si potrebbe scrivere una 
tale perla di sintesi e si sarebbe costretti a scrivere poco codice in 
piu', come il seguente:
     { ofstream f("temp.dat"); f.write("XYZ", 3); }
Non mi sembra che questa seconda versione faccia rimpiangere la prima.
Tuttavia, se introducessero adesso tale restrizione al linguaggio si 
renderebbero illegali i programmi esistenti.


 const.
Eckel sbaglia. Formalmente i temporanei sono rvalue non modificabili.
In pratica non puoi scrivere:
3 += 2;
Ma puoi chiamare su di loro funzioni membro non const, come hai gia'
notato:
struct A {
  void b() {}
};
a().b();
Secondo alcuni anche questo andava vietato, ma a volte e' comodo poter
scrivere:
a->b()->c();
Ciao,
Nicola

 ci scrive dentro tre caratteri e chiude il file.
Sì, in questo caso l'oggetto viene utilizzato per modificare un altro 
oggetto (il file system) non temporaneo quindi ha senso.
Kiuhnm

 Eckel sbaglia. Formalmente i temporanei sono rvalue non modificabili.
Sarebbe corretto se (io) dicessi che
"formalmente i temporanei sono rvalue quindi non modificabili"?
Kiuhnm

 Anche perché sbaglio o non è liberamente (aka gratuitamente) consultabile?
Va acquistato. Il pdf costa tipo sui 20 $ (non so, da me lo hanno preso in
università e quindi non lo ho dovuto comprare io personalmente).
-- 
USB Priests for only 10$


Si.
Ciao,
Nicola

 Veramente ho letto ovunque che i temporanei /sono/ const.
No. I temporanei possono essere o non essere const a seconda di come 
sono creati. Un valore di ritorno const, per esempio, darebbe luogo ad 
un temporaneo di tipo const.
Normalmente NON sono const.
 > Non ha senso che il primo caso sia vietato mentre il secondo no.
E perchè non ha senso? Nel primo caso hai una reference inizializzata 
con un temporaneo, nel secondo caso chiami un metodo del temporaneo.
Inoltre le regole per l'inizializzazione di una reference sono diverse 
da quelle di inizializzazione di una const reference.
In generale una reference non const può essere inizializzata solo con un 
l-value. Viceversa una const (non volatile) reference può essere 
inizializzata con un r-value, incluso un temporaneo.

 con un temporaneo, nel secondo caso chiami un metodo del temporaneo.
Assumendo che i temporanei siano const, la critica non è assurda perché 
viene chiamato un metodo non const. Ora so che l'assunzione è falsa 
quindi la critica cade.
Kiuhnm