Newsgroup: it.comp.lang.c++
Titolo: Dubbio su puntatori

Salve a tutti,
ho un dubbio sull'utilizzo dei puntatori. Ho una classe Pippo che ha un 
membro topolino che � un puntatore della classe Topolino, cio�:
#include "topolino.h"
class Pippo
{
    Pippo();
    Topolino* topolino;
    void doSomething();
};
Supponiamo che nella funzione main venga creato un oggetto Pippo che chiama 
una funzione foo(), dove si crea un oggetto Topolino che viene assegnato al 
membro topolino di Pippo, cos�:
int main(int argc, char *argv[])
{
    Pippo pippo;
    foo(&pippo);
    pippo.doSomething();
}
void foo(Pippo *pippo)
{
    mytopolino = new Topolino;
    pippo->topolino = mytopolino;
}
Il programma che sto scrivendo ha questa architettura. Prima di continuare a 
scriverlo ho bisogno di risolvere il seguente dubbio:
Quando nella funzione foo() viene creato l'oggetto di tipo Topolino, al 
termine dell'esecuzione di foo() tale oggetto viene distrutto? E' importante 
capirlo perch� se l'oggetto viene distrutto, nel senso che viene liberata la 
memoria che occupava, il membro topolino di Pippo rischia di non trovarsi 
pi� nulla. Poich� Pippo::doSomething() utilizza il puntatore topolino, 
rischia di mandare in crash il sistema?
Spero di essere stato chiaro.
Dall'esito delle vostre gentili risposte dipende l'architettura del mio 
programma.
Grazie a chi vorr� rispondermi. 

 termine dell'esecuzione di foo() tale oggetto viene distrutto?
Dal codice si vede che la creazione e' esplicita (tramite l'operatore 
"new"), e quindi tale oggetto non verra' distrutto se non da un 
operatore "delete".
Al termine dell'esecuzione di "foo" vengono distrutti solamente gli 
oggetti allocati implicitamente sullo stack.
-- 
Carlo Milanesi
http://digilander.libero.it/carlmila

 ha scritto nel messaggio 
news:4a986418$0$6843$5fc...@news.tiscali.it...


>>    mytopolino = new Topolino;
c'è però un'inconsistenza di notazione
le due scritture
Topolino mytopolino;
e
mytopolino = new Topolino;
non possono coesistere nello stesso scope.
La seconda presuppone una dichiarazione di tipo PUNTATORE, 
la prima un "plain" object.
Da come le hai usate (senza dichiarazione) non sembrava 
evidente che avessi colto la differenza, scusa se l'ho 
sottolineata eh.
Per il resto hai capito giusto : le variabili automatiche 
(sullo stack) hanno la stessa durata dell'esecuzione nello 
scope in cui sono visibili (e non si può estenderla 
passandone semplicemente riferimenti fuori da tale scope).
Il puntatore si riferisce a un blocco di memoria (dinamico) 
con vita non predeterminata. Il puntatore si può copiare 
(sia nei parametri che come valore di ritorno o assegnazioni 
esplicite ad altri puntatori, confidando che tale blocco 
resta riservato sin quando non viene liberato (ad es. da un 
delete, tipo entro un distruttore opportuno)
ciao
Soviet


>>    mytopolino = new Topolino;
c'� per� un'inconsistenza di notazione
le due scritture
Topolino mytopolino;
e
mytopolino = new Topolino;
non possono coesistere nello stesso scope.
La seconda presuppone una dichiarazione di tipo PUNTATORE,
la prima un "plain" object.
Da come le hai usate (senza dichiarazione) non sembrava
evidente che avessi colto la differenza, scusa se l'ho
sottolineata eh.
Per il resto hai capito giusto : le variabili automatiche
(sullo stack) hanno la stessa durata dell'esecuzione nello
scope in cui sono visibili (e non si pu� estenderla
passandone semplicemente riferimenti fuori da tale scope).
Il puntatore si riferisce a un blocco di memoria (dinamico)
con vita non predeterminata. Il puntatore si pu� copiare


 Quanti oggetti restano in memoria? 1 o 2?
2 oggetti, di cui il primo diventa subito inaccessibile e quindi non 
potra' piu' essere distrutto.
Una regola per un programma ben fatto e': "Ogni oggetto allocato con new 
deve essere distrutto con delete, e ogni oggetto allocato con new[] deve 
essere distrutto con delete[]."
Questa regola dice due cose.
La prima e' che ogni oggetto allocato con "new" o "new[]" deve essere 
distrutto esplicitamente perche' altrimenti non verrebbe distrutto 
automaticamente.
La seconda e' per la distruzione esplicita si deve usare l'operatore 
appropriato, cioe' "delete" per gli oggetti allocati con "new", 
"delete[]" per gli oggetti allocati con "new[]", "free" per gli oggetti 
allocati con "malloc" o "calloc" o "realloc".


 potra' piu' essere distrutto.
Ok, questo adesso mi � molto chiaro. In pratica ciascuna delle due 
istruzioni crea un oggetto Pippo. Per� al termine delle due istruzioni pippo 
punter� all'ultimo oggetto creato e non avr� un puntatore da utilizzare per 
"rintracciare" il precedente oggetto.
Grazie a tutti. 

 Grazie a tutti.

di nuovo, credo che una risposta univoca sia problematica.
Anche perch�, in funzione dell'OS, ci sono vari modi di
"terminare". Pensa a un device driver che "termina" ma
rimane caricato e vive in background. Deve rilasciare le
risorse o mantenerne il possesso secondo te ?
Sono ignorante (e lo si era capito dalla discussione), ma penso che in 
realt� il driver non "termini", ma resti sempre in esecuzione, no? Se 
"terminasse" il sistema operativo deve rilasciare le risorse, altrimenti a 
che scopo conservarle?
Giovanni. 

 ma resti sempre in esecuzione, no? 
"esecuzione", strettamente parlando, non è detto. Ma 
caricato si, almeno in parte, un pezzo del gestore deve 
restare residente in ram.
ciao
Soviet


 Quanti oggetti restano in memoria? 1 o 2?
Questa domanda conferma il mio dubbio.
Il mio consiglio:
prima di procedere fermati un minuto, pensaci bene e scegli tra
1 - fare tutto in java o c# o altro linguaggio managed a scelta
2 - studiare almeno un minimo di c++ da 0 resettando prima tutti i 
pregiudizi provenienti dagli altri linguaggi
Beppe

 il mio software avrebbe creato oggetti su oggetti.
Un'alternativa alla gestione "manuale" degli oggetti con lifetime dinamico
(se hai una libreria standard recente, o se hai installato Boost) � usare 
 std::tr1::shared_ptr (oppure boost::shared_ptr)
Questo ti solleva dal gestire manualmente la distruzione, al prezzo di un
minimo costo nelle operazioni di copia del puntatore. Poich� viene usato un
sistema di reference counting, occorre avere un po' di accortezza nel
gestire gli eventuali casi di riferimento circolare, per i quali
solitamente si ricorre a weak_ptr.
Max

 ha scritto nel messaggio 
news:4a9b7fb5$0$34622$4faf...@reader4.news.tin.it...

No, nono conosco Java e C#. Comunque non siate cos� catastrofici, ragazzi! 
Il programma lo sto scrivendo e ogni giorno risolvo un problema. Fino a 
questo momento quello che ho scritto funziona e ho molte idee per migliorare 
il codice. Sul fatto che dovrei leggere un manuale di base del C++ � vero. 
Il fatto � che ho forte desiderio (e necessit�) di avere risultati subito, e 
per risultati intendo il software. Dopo aver letto i vostri consigli ed 
averli applicati non mi sembra che il codice che ho scritto sia cos� 
disastroso. Probabilmente se lo avesse tra le mani un esperto del C++ 
troverebbe qualche difetto o avrebbe qualche idea per migliorarlo, ma 
considerate anche che non mi serve alta velocit� di esecuzione (non � un 
videogioco) e il memory leak (qualora stia alimentando il problema) non � 
cos� grave visto che gli oggetti che creo sono di dimensioni ridicole.
Kaos. 

 Grazie a chi vorr� rispondermi.
Quando crei un oggetto con l'operatore new lo crei sullo heap un'area di
memoria dinamica dove la gestione dello spazio allocato � a carico del
programmatore, quindi un oggetto creato con new viene cancellato solo
esclusivamente con una delete.
Tipicamente dovresti avere un distruttore dove esplicitamente cancelli
topolino.
~pippo()
{
   delete topolino;
}
Al contrario gli oggetti o le variabili dichiarate senza operatore new
vanno sullo stack una piccola area di memoria a "pila lifo" ossia
l'ultimo che arriva � il primo che si leva dai maroni dove la gestione
della memoria � automatica ossia gli oggetti vengono rimossi in maniera
trasparente secondo le regole di visibilit�, ossia quando una funzione
termina, quando esci da un blocco etc...
metodoA
{
   int pluto = 2;
   int *clarabella = new Integer(2);
}
in questo caso pluto verr� automaticamente rimosso mentre clarabella no,
verr� allocato e siccome la funzione non ritorna nessun rifermento ne
clarabella era una variabile di istanza non avrai pi� modo di liberare
quella memoria e avrai creato un memory leak, ossia una falla nella
gestione della memoria, se il tuo software per esempio chiama mille mila
milioni di volte il memtodo "metodoA" avrai un bel p� di memoria
occupata e non liberabile, ci sono alcuni tools che aiutano ad
analizzare il codice, tanto per fare reclame alla apple, nell'ultimo
xcode 3.2 c'� un tools specifico che analizza lo heap mentre il
programma � in esecuzione (ma ne esistono di anologhi).
spiegazione da bar di stack vs heap...