Newsgroup: it.comp.lang.c++
Titolo: Oggetti temporanei.

Gli oggetti temporanei ritornati da una funzione sono validi all'interno
dello scope?
Cioč se io faccio
class MyObject;
MyObject fun();
main()
{
    MyObject& obj = fun();
    obj->Metodo1();
    obj->Metodo2();
    obj->Metodo3();
}
E' corretto? Grazie, FBF.

 
Inizialmente ero convinto che un oggetto temporano venisse distrutto
comunque all'uscita dall'espressione in cui compare. Sembra però, in base
a quanto scrive Stroupstrup [TCPL,§10.4.10] e alle prove che ho fatto con
il mio compilatore, che, se usato per inizializzare in reference,
l'oggetto viene distrutto quando il reference esce di scope.
Quello che però è sbagliato nel tuo codice (e il compilatore dovrebbe
segnalartelo) è l'uso di un reference non-const. Quindi:
 const MyObject& obj = fun();
non dovrebbe produrre problemi di sorta.
Max

 Max
Ottimo. Ho letto lo Stroupstrup e dice "unless bound to a reference or used
to initialize a named object" e non ho capito la seconda parte: quando lui
scrive
string ss = s1 + s2; //s1 ed s2 sono due oggetti string
l'oggetto temporaneo viene passato come parametro al costruttore di ss che ne
crea una copia. L'oggetto temporaneo viene distrutto quando viene distrutto
ss. Ma perchè?

 
E' possibile (ma potrei dire un sciocchezza) che il motivo sia quello di
consentire al costruttore di utilizzare l'oggetto temporaneo per
inizializzare un eventuale membro const-reference. As es:
class A
{
    const B& m_ref;	
    public:
    A( const B& b ) : m_ref( b ) { };
}
Ad ogni modo, con il mio compilatore (gcc 2.91) non accade quello che dice
Stroupstrup e se inizializzo un A in questo modo
 A a = B();
l'oggetto temporaneo B viene comunque distrutto prima dell'oggetto A.
Mah. Qualcuno può far luce sulla questione?
Max

 ss. Ma perchč?
Veramente, se non sbaglio, in questo caso l'oggetto temporaneo viene
copiato nell'oggetto ss applicando il costruttore di copia e poi
distrutto.
EMG

 
Infatti questo è cio di cui io e (presumo) fbf eravamo convinti. 
E' quello che scrive Stroupstrup che ci ha un po' confuso.
 [TCPL §10.4.10]
 
   const string& s = s1 + s1
   string ss = s1 + s2;
   [...] 
   The temporary object is destroyed when "its" reference or named
   object go out of scope.
Dove "named object" si riferisce presumibilmente a "ss".
Max

    string ss = s1 + s2;
Mi sa che hai copiato l'esempio in modo sbagliato: sulla mia copia (3
ristampa) e':
const string & s = s1 + s2;
In questo caso l'oggetto temporaneo e' quello che contiene il risultato
di s1 + s2, e ne e' garantita l'esistenza fino a quando s non esce di
scope.
Ciao,
Nicola


No, Stroupstrup parla di entrambi i casi (non ho fatto nessun errore di
copiatura, l'ho preso dalla 3 edizione del 1998). Uno è quello del binding
del reference, che abbiamo discusso ieri e che non è problematico. L'altro
è quello dell'inizializzazione di un oggetto concreto mediante oggetto
temporaneo.
Max

Abbiamo due ristampe diverse (la mia e' 3 printing, September 1997)
della stessa edizione dello stesso libro, "The C++ Programming Language,
third edition". La mia non fa riferimento a "named object" nei passaggi
che hai citato.
Se la tua ristampa e' piu' recente, probabilmente B.S. ha aggiornato il
libro a causa di modifiche allo standard, la cui motivazione pero' mi
sfugge. Sulla sua home page c'e' se non sbaglio la lista delle
correzioni, ma non ho l'URL a portata di mano.
Ciao,
Nicola

 third edition".
Sapete per caso cosa riporta di diverso la terza edizione dello
Stroustrup rispetto alla seconda? E' chiaro che per rispondermi dovreste
avere entrambe le edizioni ;-)
--
Saluti,
Danilo!
* Per risposte in e-mail elimina "-rimuovi" dall'indirizzo *

 E' quello che scrive Stroupstrup che ci ha un po' confuso.
Esattamente. Ho buttato giù il seguente codice:
#include <iostream>
class obj
{
public:
 obj(int i)
  : m_i(i)
 { std::cout << "costruzione" << m_i << std::endl; }
 ~obj()
 { std::cout << "distruzione" << m_i << std::endl; }
 obj(const obj& o)
 {
  std::cout << "costruttore di copia" << o.m_i << std::endl;
  m_i = o.m_i;
 }
 int m_i;
};
obj temp (int i)
 { return obj(i); }
int main()
{
 obj a = obj(1);
 obj b(2);
 temp (3);
 obj c = temp (4);
 return 0;
}
che produce come output:
costruzione1
costruzione2
costruzione3
distruzione3
costruzione4
distruzione4
distruzione2
distruzione1
In pratica quindi ne deduco che in realtà il costruttore di copia non viene chiamato
per copiare l'oggetto ma che scrivere
const obj& a = obj(5);
obj b = obj(5);
sia in realtà la stessa cosa, con il vantaggio di poter modificare l'oggetto b. Buono
a sapersi.
Ciao FBF.

 a sapersi.
E` un'ottimizzazione consentita e consigliata dallo standard: usare
direttamente il costruttore obj::obj(int) e omettere il copy ctor,
*purche`* quest'ultimo sia correttamente accessibile.
Alex

 avere entrambe le edizioni ;-)
Come argomenti effettivi l'aggiunta piu' importante e' data dai
riferimenti alla libreria standard ed ai namespace. In realta' la
seconda edizione e' diventata sostanzialmente inutilizzabile (se si
lavora su un compilatore ragionevolmente aggiornato) perche' nel
frattempo e' cambiato l'approccio all'uso del linguaggio. In particolare
l'esperienza maturata ad esempio sui template, che guarda caso sono la
base portante della libreria, ha spostato l'accento da un approccio
abbastanza centrato sull'orientamento agli oggetti ad un approccio
ibrido dove la programmazione generica ha un ruolo importante.
In piu' lo standard e' stato finalmente approvato ed e' sostanzialmente
riflesso nella terza edizione, rendendo la seconda inaffidabile come
riferimento.
Ciao,
Nicola