Newsgroup: it.comp.lang.c++
Titolo: Heap o Stack

Esiste un modo infallibile per capire se un oggetto è stato creato nello
stack o nell'heap?


Forse è meglio se specifico il problema:
Ad un certo punto di un mio programma avviene questo:
delete c;
ma c può essere stato creato come (esempio)
Obj c;
  oppure
Obj *c = new Obj();
vorrei che delete saltasse gli oggetti instanziati come nel primo caso.
Azzardo: ridefinizione dell'operatore new?

 stack o nell'heap?
No, non esiste alcuna tecnica portabile per determinare se un puntatore si
riferisce a un oggetto che è nello stack, nello heap o allocato
staticamente.
Max

 caso. Azzardo: ridefinizione dell'operatore new?
Ecco un'ideuccia che forse potebbe fare al caso tuo. Se definisci la
classe derivando dal template qui sotto, come descritto nell'esempio, ti
ritrovi una classe che può essere allocata nello heap (tramite funzione
statica create()) o nello stack, e dotata del metodo dispose() che
distrugge l'oggetto soltanto se non è stato allocato con create().  
Inoltre, create() e dispose() sono gli unici modi per creare e distruggere
gli oggetti, in quanto new e delete non sono accessibili.
	template< class Derived , class Base >
	class heap_conscious_impl : public Base
	{       private:
		bool in_the_heap;
		protected:
		void* operator new( size_t len ) throw ( std::bad_alloc )
		{
			return ::new char [ len ];
		}
		void operator delete( void* p )
		{	::delete [] p;
		}
		heap_conscious_impl() : in_the_heap(false)
		{ }
		public:
		static Derived* create() 
		{
			Derived* newobj = new Derived;
			newobj->in_the_heap = true;		
			return newobj;
		}
		void dispose()
		{	
			if( in_the_heap )
			{	
				Derived* dthis = static_cast<Derived*>(this);
				delete dthis;
			}
			else
			{	// NOOP
			}
		}
	};
	class empty_base  { };
	class A : public heap_conscious_impl< A, empty_base >
	{
		public:
		~A()
		{	cerr << this << ": dying..." << endl;
		}
	};
	void destroy( A* p )
	{
		p->dispose();
	}
 
	int main()
	{
		A a;
		A* ap = A::create();
		destroy( ap ); // distrugge *ap
		destroy( &a ); // non fa niente
	}
Max

 Obj *c = new Obj();
La prima ti da un ovvio errore in compilazione; operator delete
richiede un pointer.  Nel caso avessi voluto scrivere Obj *c; , no,
non c'e' mezzo di saperlo.
-- 
Maurizio Loreti                         
http://www.pd.infn.it/~loreti/mlo.html
Dept. of Physics, Univ. of Padova, Italy          loreti at pd dot infn dot it

 Azzardo: ridefinizione dell'operatore new?
Lascia perdere. Invece vai su 
www.bost.org
, scarica la libreria e studia
come funzionano scoped_ptr e shared_ptr che molto probabilmente sono il
modo giusto di realizzare quello che ti ha portato a porti il problema
che hai postato.
Ciao,
Nicola

 Ecco un'ideuccia che forse potebbe fare al caso tuo.
La tengo buona come soluzione.
Mi spiegheresti questo:
void* operator new( size_t len ) throw ( std::bad_alloc )
{
return ::new char [ len ];
}
(a parte il throw) Perchè restituire un array di caratteri?

 Lascia perdere. Invece vai su 
www.bost.org
Sicuro sia l'indirizzo giusto?


No, e' 
www.boost.org
 :-(
Ciao,
Nicola

 
Beh, uso new[] per allocare un array di caratteri, e il puntatore
restituito viene convertito in void*. Un modo come un altro per allocare
memoria. Avrei potuto scrivere anche:
  return ::malloc( len );
Max

 (a parte il throw) Perchè restituire un array di caratteri?
Perche' e' stabilito dallo standard che sizeof(char) == 1 unita' di 
allocazione (non mi sembra che parli esplicitamente di byte), quindi 
restituendo un'array di caratteri restituisce in sintesi len "bytes".
-- 
Andrea Bergia - studente
Linux Registred User #281550

  return ::malloc( len );
Meglio secondo me sarebbe
   return ::operator new (len);
che chiama l'allocatore generico di raw memory C++.
Inoltre la sintassi che usi
  ::delete[] p;
non credo sia permessa quando p e' un void *:
per poter usare l'operatore delete[] dovresti
secondo me fare prima un cast a char *.
Se invece usi l'allocatore di raw memory la
sintassi per invocare il deallocatore e'
   ::operator delete[](p);
Personalmente trovo l'idea di definire un allocatore
di raw-memory di classe solo per poterlo dichiarare
protected abbastanza discutibile. Tieni anche presente
che la cosa si puo' anche aggirare facendo...
   ::new A;
infatti a quello che ho capito questa notazione
implica che l'allocatore utilizzato e' comunque
quello globale (e quindi non viene verificata
l'accessibilita' dell'allocatore custom di
classe in questo caso).
Andrea

    ::new A;
Eh sě. Non ci avevo pensato.
Max