|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
[C++] Da puntatore a reference.
Giorno,
stò pianificando dei metodi per restituire una reference degli oggetti della classe, invece di restituirne i puntatori per maggiore sicurezza ed evitare che possano essere cancellati, ho quindi un metodo tipo questo: Codice:
Object &Classe::object()
{
return *_object; // oggetto privato
}
_object ho dovuto dichiararlo come puntatore perchè la sua inizializzazione avviene in un metodo chiamato "init" e non nel costruttore di Classe. Se volessi dichiarare in Classe: Codice:
Classe {
public:
// ...
Object object;
};
object in quest'ultimo caso dovrebbe essere inizializzato nel costruttore di Classe giusto? Se cosi fosse mi basterebbe dichiarare un blocco try catch nel costruttore e gestire l'eventuale eccezione... ma come? Aspetto vostre notizie Grazie in anticipo.
__________________
|
|
|
|
|
|
#2 |
|
Bannato
Iscritto dal: Oct 2002
Città: Vicino Fermo Mercatino:più di 100 trattative tutte OK
Messaggi: 4651
|
Allora innanzitutto l'oggetto "object" devi dichiararlo come variabile di classe, all'interno dell'header della classe e non crearlo all'interno del costruttore.
Altrimenti avresti uno scope locale al costruttore e non puoi restituirlo. Poi quando lo restituisci: return *object, (se hai creato un puntatore ad object e "object" è l'indirizzo), altrimenti return object (se object è l'oggetto stesso). nel caso vuoi instanziare l'oggetto all'interno del metodo stesso, devi scrivere Object &Classe::object() { Object* object = new object(); return object; } in questo caso passi il riferimento e non la copia dell'oggetto, ma avendolo creato tramile la "new", l'oggetto viene allocato nello heap e non muore mai. neanche se distruggi il parent. Ti dovrai quindi ricordare di distruggerlo (" delete(object)" ) in seguito. Cmq datti una letta a qualche libro per iniziare il C++...non ti puo' fare che bene. |
|
|
|
|
|
#3 |
|
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Temo tu mi abbia frainteso.
Si object è un membro della classe, privato. Nella dichiarazione della classe lo definisco come puntatore perchè la vera inizializzazione tramite new avviene non nel costruttore di Classe ma in un metodo chiamato "init". Quello deve quindi essere il primo metodo, cosi crea l'oggetto nello heap e assegna al puntatore il suo indirizzo. Ho però bisogno di restituire una reference, non una copia (non c'e n'è necessità) nè un puntatore, che potrebbe essere cancellato. Il mio dubbio sorgeva dal fatto che sino ad oggi tutti gli esempi di funzioni che restituiscono una reference sono cosi strutturate: Codice:
Object &Class::Reference()
{
Object &ref = *_object; // object è un membro della classe
return ref;
}
Codice:
Object &Class::Reference()
{
return *_object;
}
La seconda domanda invece era: Se nella dichiarazione (non definizione) della classe anzichè mettere: Codice:
Object *_object; Codice:
Object _object; IMHO è da fare nel costruttore della classe che dichiara l'oggetto _object, ma non essendo io a inizializzare l'oggetto ho qualche perplessità su come catturare quell'eccezione. Se non sono stato chiaro, faccio un piccolo esempio. Grazie per la risposta.
__________________
|
|
|
|
|
|
#4 | |||
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
Questo è un memory leak Quote:
Quote:
Ultima modifica di cionci : 06-08-2010 alle 19:55. |
|||
|
|
|
|
|
#5 |
|
Senior Member
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
|
Il codice che hai utilizzato va benissimo, e non ritorna una copia, non ti preoccupare
Per la seconda domanda, hai bisogno di un "function try block", cioè di associare il try non ad un blocco ma all'intera funzione: Codice:
MyClass::MyClass()
try : object() {
//Corpo del costruttore
}
catch (myObjectException &e){
//Gestione dell'eccezione
}
__________________
If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization. --Gerald Weinberg |
|
|
|
|
|
#6 | |||
|
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Ooottimo
Quote:
Codice:
class Window {
public:
Window() { throw 1; } // supponiamo una eccezione
};
class Handler {
public:
Handler() {};
Window window; // (1) -- alla costruzione lancerà un'eccezione
};
Se avessi un puntatore, farei tipo: Codice:
// Window *window; // dichiarato precedentemente
Handler::Handler() {
try {
window = new Window;
}
catch (Exception &ex) {
// gestisci
}
}
Quote:
Quote:
Se io non inizializzo esplicitamente object() ? Funzionerà ugualmente? Grazie mille per la risposta
__________________
Ultima modifica di Opcode : 06-08-2010 alle 20:45. |
|||
|
|
|
|
|
#7 | |
|
Senior Member
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
|
Quote:
"A rigore" dovrebbe funzionare, nell'indecisione comunque aggiungere la chiamata al costruttore non costa molto e rende più chiaro "da chi" ti aspetti un'eccezione. Un problema più interessante è che, quando si associa un "function try block" ad un costruttore, al termine del blocco catch, se questi non ha propagato l'eccezione ricevuta (o non ne ha lanciata una nuova), l'eccezione originaria è comunque propagata: in soldoni, quando fallisce il costruttore di una sottoparte, deve fallire il costruttore dell'intero oggetto -quindi ricordati di avere un blocco try associato alla costruzione di MyClass, e possibilmente lancia una eccezione "ad hoc" nel blocco catch!-. Una questione simile dovrebbe valere anche per i distruttori, anche se ha implicazioni meno significative (una eccezione in un distruttore dovrebbe sempre terminare il programma, e in generale il codice di un distruttore è meno propenso a fallire).
__________________
If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization. --Gerald Weinberg |
|
|
|
|
|
|
#8 |
|
Bannato
Iscritto dal: Oct 2002
Città: Vicino Fermo Mercatino:più di 100 trattative tutte OK
Messaggi: 4651
|
|
|
|
|
|
|
#9 | ||
|
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Confermo che funziona
Comunque si, per maggiore chiarezza lo inizializzerò esplicitamente. Quote:
Hai fatto benissimo a dirmelo, non ne ero a conoscenza. Sapevo invece che se c'è un problema nel costruttore e hai allocato qualche risorsa, l'eccezione non chiama il distruttore perchè l'oggetto non è stato creato, e quindi ci vuole attenzione. Riguardo a questo problema, ti giro una nuova domanda: e se MyClass fosse un singleton? La classe viene inizializzata staticamente, come potrebbe gesitre il throw del proprio costruttore? Quote:
Grazie.
__________________
|
||
|
|
|
|
|
#10 | |
|
Senior Member
Iscritto dal: Oct 2005
Messaggi: 3306
|
Quote:
Anche perchè poi tutti gli eventuali riferimenti avrebbero un comportamento indefinito, il crash del programma è assicurato. Infine chi ti dice che l'oggetto a cui punta il riferimento è stato allocato con una new? |
|
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
|
Allocazione è deallocazione vanno SEMPRE svolte allo stesso livello di "astrazione": allocare all'interno di una classe e lasciare la responsabilità della deallocazione all'utente è una pratica da evitare assolutamente; al massimo si può ritornare un oggetto gestore che deallochi il riferimento quando out of scope.
__________________
If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization. --Gerald Weinberg |
|
|
|
|
|
#12 |
|
Senior Member
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
|
chi ti dice che lo sia quello gestito tramite puntatore?
|
|
|
|
|
|
#13 | |
|
Senior Member
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
|
Quote:
Codice:
MySingleton* MySingleton::Instance() {
if (_instance == 0) {
try {
_instance = new MySingleton();
}
catch (mySingletonConstructionException) {
//...
throw;
}
}
return _instance;
}
Ovviamente, il costruttore MySingleton::MySingleton() può avere o non avere un function try block associato: lo avrà se inizializza altri oggetti (cioè se eredita da altre classi o se inizializza membri con una sintassi constructor initializer, ossia i fatidici ":"), altrimenti conterrà semplicemente uno statement try.
__________________
If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization. --Gerald Weinberg |
|
|
|
|
|
|
#14 |
|
Senior Member
Iscritto dal: Oct 2005
Messaggi: 3306
|
|
|
|
|
|
|
#15 | ||
|
Bannato
Iscritto dal: Oct 2002
Città: Vicino Fermo Mercatino:più di 100 trattative tutte OK
Messaggi: 4651
|
Quote:
Quote:
|
||
|
|
|
|
|
#16 | |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
A questo punto le domande sono tre: - chi dealloca il puntatore - chi dealloca la memoria puntata dal puntatore - che tipo di deallocazione va fatta ? una delete o una delete[] sui dati ? Chi ti garantisce che la venga fatta quella giusta ? Imho va semplicemente evitata. Se si è costretti ad usarla significa che bisogna fare un refactoring del nostro codice. Ultima modifica di cionci : 07-08-2010 alle 07:40. |
|
|
|
|
|
|
#17 | |
|
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Quindi il controllo delle eccezioni mi forza ad usare un puntatore come singleton, cioè se io volessi fare qualcosa come:
Codice:
Class MySingleton {
private:
static MySingleton _instance;
MySingleton() {};
MySingleton(const MySingleton&); //disabilito il copy constructor
public:
static MySingleton &instance() { return _instance; }
};
// inizializzo il singleton
MySingleton MySingleton::_instance; // (1)
Quote:
EDIT: ora che ci ripenso forse una soluzione c'è. Se non erro in mancanza di un handler per l'eccezione viene chiamato terminate() dalla <exception>, quindi se io gestissi in quel punto l'eccezione eventualmente generata, dovrebbe funzionare quanto meno per evitare un crash perchè non ho gestito l'eccezione, non credi? Io intanto faccio qualche test Scherzavo, non posso cattuare l'eccezione
__________________
Ultima modifica di Opcode : 07-08-2010 alle 18:41. |
|
|
|
|
|
|
#18 | |
|
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
|
Quote:
Un po' come un bambino che ti presta il pallone per giocarci a calcio assieme. Pui fare quello che vuoi, ma non puoi portartelo via, e quando se ne va l'altro, il pallone sparisce assieme a lui. Per motivi analoghi non dovresti prenderne il puntatore e salvarlo da altre parti, salvo rare eccezioni. (Discorso analogo si potrebbe fare per gli argomenti passati per riferimento, che in generale non si puo' pensare abbiano vita maggiore della chiamata stessa )
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
|
|
|
|
|
|
#19 |
|
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
|
Direi piuttosto che e' importante che sia chiaro chi e' il proprietario dell'oggetto ritornato.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
|
|
|
|
|
#20 | ||
|
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
|
Quote:
Ci si puo' stare attenti ma e' un sacco di lavoro Quote:
Direi meglio evitare. (e se invece l'oggetto era garbage collected che senso ha ?)
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
||
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 00:51.




















