Newsgroup: it.comp.lang.c++
Titolo: I puntatori mi stanno facendo girare la testa...

Ho il seguente problema:
ho un puntatore P così dichiarato:   TIPO *P= new TIPO .......
devo creare una funzione che:
1) deve restituire necessariamente un void  (void funz(....){})
2) al suo interno deve istanziare un nuovo puntatore: TIPO *q
 e liberare l'istanza dell'oggetto puntato da p, quindi far puntare p a *q.
Tutto questo deve essere trasparente esternamente a p, nel senso che
eseguita la funzione (alla quale in qualche modo passo p), *p è un oggetto
diverso da quello puntato prima della chiamata.
Spero che la mia confusione mentale non si sia riversata su quanto scritto.
qualcuno saprebbe aiutarmi ?
Ho sentito parlare dei reference (io uso il bcb4) ma non posso dichiarare
nella funzione TIPO & (*q), mi da errore di illegalità!

  e liberare l'istanza dell'oggetto puntato da p, quindi far puntare p a *q.
 void funz( TIPO * & p )
 {
    delete p;
    p = new TIPO;
 }
Max

 qualcuno saprebbe aiutarmi ?
Ho provato questo e funziona...
// pointer.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
using namespace std;
struct TIPO{
 int a;
 TIPO(int aval) : a(aval) {}
};
void func(TIPO** cp){
 delete *cp;
 TIPO* q = new TIPO(2);
 *cp = q;
}
int main(int argc, char* argv[])
{
 TIPO *p = new TIPO(1);
 cout << p->a << endl;
 func(&p);
 cout << p->a << endl;
 return 0;
}
Non so se soddisfa le tue esigenze...In ogni caso, ti risparmio la solita
solfa su: il modo standard di allocare memoria in C++ e' usare vector,
non bisognerebbe usare new se non in rarissimi casi (un po' come il goto...)

 nella funzione TIPO & (*q), mi da errore di illegalità!
Non puoi dichiarare "puntatore a reference a TIPO".
Puoi, invece, vedi sopra, dichiarare "reference a puntatore a TIPO".
Alex

nella funzione TIPO & (*q), mi da errore di illegalità!
La dichiarazione della funzione giusta e'
f( TIPO* &p );
Per aiutarti fai ( alla pascal )
typedef TIPO * TIPOP;
f( TIPOP &p );

non bisognerebbe usare new se non in rarissimi casi (un po' come il goto...)
???

Andrea Laforgia wrote:

Puoi spiegare quali sono le differenze tra le due versioni e perche' una e'
preferibile all'altra?

preferibile all'altra?
Nessuna differenza, ma visto che il C++ mette a disposizione il
passaggio per riferimento (contrariamente al C) perche' simularlo ?
Usiamolo ;)
Piu' che altro, mi spieghi perche' new andrebbe evitata ?

Andrea Laforgia wrote:

credo che su questo punto il buon Alex Martelli potrebbe discettare a lungo.
In generale new e' un costrutto di basso livello che accede direttamente alla
memoria;
in particolare in questo caso nessuno ti assicura che l'oggetto che
entra nella funzione sia stato allocato con new: se fosse un puntatore automatico
ad un area di memoria creata per esempio con una array costante avresti
il duplice problema di deletare qualcosa che non deve essere deletato, e di avere
un memory leakage qualora il puntatore venisse automaticamente distrutto.
Vista la loro pericolosita', funzioni come func dovrebbero essere scritte raramente,
tanto raramente che il programmatore che dovesse incorrere nella necessita' di
scriverle dovrebbe passare un po' di tempo a recuperare le informazioni
necessarie alla bisogna...
Una eccezione che io personalmente contemplo (ma non e' condivisa universalmente)
e' quella di ammettere l'analisi di questi casi a scopo di studio...
Beh, ho soloneggiato abbastanza!

Vista la loro pericolosita', funzioni come func dovrebbero essere scritte raramente,
Su questo siamo assolutamente d'accordo, ma da qui a dire che new non
andrebbe usato (addirittura relegarlo al livello di "goto") mi sembra
un po' eccessivo ;)

 un memory leakage qualora il puntatore venisse automaticamente distrutto.
Si`, questo e` un altro problema, per certi versi "duale".  Idealmente,
vorremmo potere incapsulare, cosi` come la creazione degli oggetti (vedi
sopra), anche la loro distruzione, benche` gli obbiettivi qui siano un
poco diversi.  Anche qui, la distruzione puo` essere delegata alla
fabbrica (idioma usato di rado, ma interessante) o all'oggetto stesso
(caso molto piu` comune) con metodi virtuali come "destroy".
Il problema e` meno acuto di quello della creazione; se incapsulando la
creazione possiamo garantire che tutti gli oggetti provengono da "new",
allora in certi casi puo` essere accettabile che la loro distruzione
venga fatta direttamente con "delete".
Tutto questo NON si applica a new[] e delete[], le versioni-array, il
cui uso e` invece da sconsigliarsi nel 99.44% dei casi (o piu`).  Cosa,
ad esempio, poco nota ma importante, e` che gli allocator della libreria
standard NON usano tipicamente queste iatture di new/delete di array,
ma tecniche (sempre di basso livello, certo!) assai piu` raffinate,
come ad esempio il "placement-new".
Alex