Newsgroup: it.comp.lang.c++
Titolo: Return di oggetto creato al volo e memory leak


IntegerSet e` una classe che definisce un insieme di interi, questo 
metodo genera l'intersezione tra this e e un altro oggetto IntegerSet, 
per poi restituire un terzo insieme che e` l'intersezione tra i due.
No fate caso all'implementazione, in realta` funzionano in maniera un 
po` anomala.
Le mie domande sono: restituire un oggetto in quel modo costituisce un 
memory leak? L'oggetto creato non viene mai distrutto... tra parentesi, 
devo ritornare il puntatore per questioni di chaining delle chiamate.
Quali altri metodi posso adottare?
Grazie dell'attenzione

 Grazie dell'attenzione

 Soviet
saluti e ringraziamenti!


Prima di tutto, qui ci si rivolge a tutto il gruppo, quindi avresti 
dovuto dire "Provo a porvi un'altra domanda" o "Provo a porre un'altra 
domanda". Alternativamente, scrivi in privato.
Comunque, di regola l'operator+ rende un valore. Per esempio, questo è 
valido sia per le stringhe che per i numeri complessi.
Il file "string" della librearia standard del compilatore C++ Microsoft 
contiene le seguenti righe:
   template<class _Elem,
	class _Traits,
	class _Alloc> inline
	basic_string<_Elem, _Traits, _Alloc> __CLRCALL_OR_CDECL
   operator+(
		const basic_string<_Elem, _Traits, _Alloc>& _Left,
		const basic_string<_Elem, _Traits, _Alloc>& _Right)
	{	// return string + string
	return (basic_string<_Elem, _Traits, _Alloc>(_Left) += _Right);
	}
che pressapoco corrispondono a:
   string operator+(const string& _Left, const string& _Right) {
     return string(_Left) += _Right;
   }
e il file "xcomplex" della librearia standard del compilatore C++ 
Microsoft contiene le seguenti righe:
		// TEMPLATE FUNCTION operator+
   _TMPLT(_Ty) inline
	_CMPLX(_Ty) __CLRCALL_OR_CDECL operator+(
   const _CMPLX(_Ty)& _Left,
   const _CMPLX(_Ty)& _Right)
	{	// add complex to complex
	_CMPLX(_Ty) _Tmp(_Left);
	return (_Tmp += _Right);
	}
che pressapoco corrispondono a:
   template<typename T>
   complex<T> operator+(
     const complex<T>& _Left,
     const complex<T>& _Right)
   {
     return complex<T>(_Left) += _Right;
   }
Da come vedi, in entrambi i casi l'operatore "+" e' esterno alla classe, 
crea una copia temporanea dell'operando di sinistra dell'operazione, usa 
l'operatore interno "+=" per sommarci l'operando di destra, e 
restituisce l'oggetto temporaneo per valore.
In tal modo si evitano i rischi di memory-leak, al costo di creare un 
oggetto temporaneo.
pertanto, sia con stringhe, che con numeri complessi, che con altri tipi 
di oggetti che supportano tale operatore nella sua semantica 
convenzionale, se il compilatore non e' particolarmente ottimizzante, la 
seguente istruzione:
   a = b + c + d;
risulta meno veloce della seguente:
   a = b; a += c; a += d;
che e' equivalente alla seguente:
   ((a = b) += c) += d;
--
Carlo Milanesi

 l'insieme risultante).
Con gli smart-pointer, puoi scrivere:
object.method1().method2(other_object)->print()
  bye
	av.

> object.method1().method2(other_object).print()
come dissi sopra, anche un puntatore lo permette.
Basta usare -> invece del punto
Ciò detto, giusto perché hai scritto che stai studiando il 
C++, considera che qualche volta alcune funzioni (anche 
della vecchia libreria std) restituivano una reference ad 
un'istanza interna (locale alla funzione) ma statica.
Questo ha senso solo se vuoi rendere "globale" la reference, 
ed il suo valore aggiornato tra diverse chiamate. Ovviamente 
ciascuna chiamata sovrascrive il valore precedente. Se ti 
serve il valore a un certo istante, devi copiarti i dati al 
momento del ritorno, perché possono essere modificati in 
qualsiasi momento e punto diverso del codice (ad es. codice 
rientrante a eventi)
Mi ricordo che, per eliminare l'overhead di 
allocazione/deallocazione, qualche funzione di conversione 
verso stringa (stile C) o altri formati, aveva un buffer 
interno di cui ritornava l'indirizzo. La routine non 
allocava niente, il buffer era persistente in quanto a 
esistenza, ma il suo valore poteva cambiare in modo non 
prevedibile, ergo andava ricopiato appena dopo il return
ciao
Soviet


 domanda". Alternativamente, scrivi in privato.
Mi dispiace, lo terro` presente d'ora in poi.

Ottimi esempi, ora diverse cose mi sono piu` chiare.
Comunque, ancora non mi riesce di tirar fuori qualcosa che funzioni come 
voglio io, ho implementato una classe Array che fa ridefinisce una serie 
di operatori, e tutto funziona tranne l'operatore +, che fa uso del +=, 
la riporto qui integralmente, chiunque abbia voglia di dargli 
un'occhiata anche in genere....
Lo snippet incriminato e` questo
const Array&
Array::operator + (const Array& other) const {
     return Array(*this)+=other;
}
La classe completa:
Array.h
http://sprunge.us/VJKR
  (copiabile)
http://sprunge.us/VJKR?cpp
 (con evidenziazione della sintassi)
Array.cpp
http://sprunge.us/hahd
http://sprunge.us/hahd?cpp
main.cpp
http://sprunge.us/iKcb
http://sprunge.us/iKcb?cpp
Makefile
http://sprunge.us/GggE
http://sprunge.us/GggE?makefile
Non riporto il codice direttamente qui per via della lunghezza, ditemi 
pure se ho fatto male.
Il risultato dell'operazione di addizione e` un undefined behaviour.
Grazie ancora
saluti

 av.

 saluti


scusa, mi son riletto, e qui volevo dire ovviamente 
ASSEGNAZIONE, non associazione


 }
Avresti dovuto ritornare per valore, non per riferimento. Cosi':
   const Array
   Array::operator + (const Array& other) const {
     return Array(*this)+=other;
   }
oppure cosi':
   Array
   Array::operator + (const Array& other) const {
     return Array(*this)+=other;
   }
Tieni presente che l'espressione "Array(*this)" crea un oggetto che 
viene distrutto al termine dell'istruzione in cui si trova.
Ritornando per riferimento, l'espressione che chiama l'operator+ 
utilizza un riferimento a un oggetto che e' appena stato distrutto.
Invece ritornando per valore l'oggetto temporaneo viene copiato appena 
prima di essere distrutto.
--
Carlo Milanesi


Tutto chiarissimo, ora so meglio come destreggiarmi nelle varie situazioni.
Non ho altre domande, grazie ^^


Hai ragione per il const, era un errore mio, come mi ha fatto notare 
Carlo Milanesi il return type era sbagliato. Non ho pero` capito dov'e` 
che modifico uno degli operandi:
l'espressione "return Array(*this);" non modifica this in alcun modo!


No, tu avevi scritto :
const Array&
Array::operator + (const Array& other) const {
     return Array(*this)+=other;
}
da cui si vede che manifestamente modichi this assegnandovi 
il risultato di sé stesso più other.
Per inciso, noto adesso che non avrebbe neanche potuto 
compilare per il secondo CONST, quello non sul tipo di 
ritorno, ma il modificatore funzionale. Aggiunto a una 
dichiarazione vuole garantire che non modifichi this, cosa 
che appunto facevi, quindi non avrebbe compilato a prescindere
ciao
Soviet


Ma tutt'ora io faccio
Array
Array::operator + (const Array& other) const {
     return Array(*this)+=other;
}
E compila, e this non viene modificato: Array(*this) dovrebbe costruire 
un nuovo oggetto che utilizza il costruttore di copia di Array, il quale 
oggetto serve soltanto per evitare la modifica di this, dato che (come 
giustamente hai detto tu) l'operatore + non prevede questo 
comportamento, e viene distrutto subito dopo l'istruzione return.

 comportamento, e viene distrutto subito dopo l'istruzione return.
Mi era sfuggita quella parola Array (forse perché compare 4 
volte in 2 righe, lol)
Beh cmq vedo che hai capito bene la logica :-)
ciao
Soviet


L'ho capita grazie a voi ;)
alla prossima, saluti