Newsgroup: it.comp.lang.c++
Titolo: Distruttore su commissione

Salve, 
mi chiedo e vi chiedo: 
posso invocare il distrutto re di una classe a mio piacimento oppure
il distruttore è messo a disposizione del solo compilatore?
Se non posso invocarlo, possi farmi una funzione membro che posso
chiamare quindi, che agisce allo stesso modo del distruttore, ma ci
saranno problemi quando il distruttore entrerà in gioco?
Tnx in anticipo

il distruttore è messo a disposizione del solo compilatore?
L'operatore 'delete' richiama il distruttore della relativa classe.
Luc.

Normalmente viene chiamato automaticamente quando finisce la vide di
un'oggetto
(con delete se lo hai allocato dinamicamente, quando esci dallo spazio di
visibilità
 dove è stato creato se dinamico)
Cmq lo puoi chiamare anche esplicitamente
~class();
"Luc" <TOGL...@katamail.com-TOGLI> ha scritto nel messaggio
news:ogvk9tgurdslm8o2i...@4ax.com...


il distruttore è messo a disposizione del solo compilatore?
Il compilatore invoca automaticamente il distruttore per oggetti non
allocati dinamicamente
che escono dall'ambito di visibilità
<CODE>
void foo()
{
    Distruggimi Vittima;
    /*.....*/
}
// Terminata la chiamata alla funzione foo, il compilatore invoca il
distruttore
</CODE>
Ciao
Daio

L'operatore 'delete' richiama il distruttore della relativa classe.
Beh, lui però voleva chiamare il distruttore, non deallocare l'oggetto (è
diverso). E il distruttore si può chiamare, ma si consiglia di non farlo. Ci
sono casi particolari in cui può essere utile, se non addirittura essenziale
farlo (ad es., nell'implementare un contenitore generico sul modello di
std::vector, che abbia un minimo di efficienza).
Ciao
Domenico Barra


Il distrutto re? Cos'č, un'espressione poetica? ;-)
Comunque, sě, il distruttore puň essere tranquillamente invocato, ma nella
maggior parte dei casi si cerca di evitare di farlo...
Ciao
Domenico Barra

diverso).
Si, l'ho pensato dopo. E' un operazione strana ma comunque valida,
anche io alcune volte l'ho usata... un bel metodino Destroy() 8-)
Luc.

maggior parte dei casi si cerca di evitare di farlo...
se non sbaglio (e potrebbe essere) si chiama il distruttore
esplicitamente soprattutto quando si deve fare un "placement new":
class ABC;
ABC* p= new ABC;
p->~ABC();
ABC* p2= new(p) ABC;
costruisce un nuovo oggetto senza deallocare la memoria. Già che ci
siamo ho un dubbio; sarebbe corretta un cosa del genere:
int* p_int=new(p) int;
cioè usare il placement new con due tipi diversi?
Anto
--
Antonio Cuni, 18 anni, studente
Brainbench Certification: 
Master C++: 4.6, higher than 98% of all previous test takers.
C Language: 3.32, higher than 79% of all previous test takers.
http://www.brainbench.com/transcript.jsp?pid=1301688

 cioè usare il placement new con due tipi diversi?
Questo e' inutile. Il placement new serve in sostanza a far si che venga
chiamato il costruttore.
Ciao,
Nicola

 cioè usare il placement new con due tipi diversi?
credo di sì, perchè il parametro p in quel caso viene visto come void
*, quindi ci puoi mettere un qualsiasi puntatore!

chiamato il costruttore.
non capisco. il costruttore di quale classe? Non basterebbe dichiarare
un altro oggetto per eseguire il ctor?
Credevo che il placement new potesse avere senso per costruire un
altro oggetto e non invalidare puntatori già presenti.


 altro oggetto e non invalidare puntatori già presenti.
Questo pare a me (e a Herb Sutter :-) un approccio pericoloso: la vita
di un'istanza inizia con l'esecuzione del costruttore e termina con
l'esecuzione del distruttore. L'uso di placement new per "resettare" una
zona di memoria puo' essere un'ottimizzazione di bassissimo livello, ma
va fatta con attenzione.
Sfruttare questi trucchi a livello piu' alto puo' portare disastri, ad
esempio:
struct A { int a; };
struct B : public A { int b; };
B b;
A * pa = &b;
A * pa2 = new (pa) A; // Ahia! e b.b ?
Ti consiglio di leggere "Exceptional C++" di Herb Sutter (e' stato anche
tradotto). Andrea Griffini ha forse ragione a dire che non e' un libro
straordinario, ma qualche consiglio utile lo da.
Ciao,
Nicola

"Simone Finotti" <x...@xxx.xx> wrote in message
news:k0Tn6.52366$Y93.1...@news.infostrada.it...

Se fai:
void *p=new(sizeof(A));
A *p1=new(p) A;
p1->~A();
B *p2=new(p1) B;
p2->~B();
delete(p);
Vedo solo un possibile problema: devi assicurarti che le dimensioni siano
"compatibili". Ovvero che sizeof(A) sia maggiore o uguale a sizeof(B), oppure
cambiare l'allocazione di p di conseguenza.
Se invece fai come hai fatto tu, vedo VARI possibili problemi. Alcuni validi
anche nel caso che tu faccia semplicemente
A *pa=new A;
pa->~A();
Tanto per cominciare, quel puntatore lo dovrai per forza "liberare" con un
delete che corrisponde al new fatto. Quindi dovrari "ricostruire" la A o
assicurarti che il distruttore abbia lasciato una A "valida".
Inoltre credo, ma non ho controllato, che per lo stesso motivo tu non possa
comunque fare qualche cosa che rende la A "invalida" (per esempio costruendoci
una B) se prima non hai fatto la delete.
Quello che e' assolutamente certo e' che devi assicurarti che non esista nessun
altro puntatore alla A che stai "distruggendo" con pa->~A(). Questo non e'
banale perche' tale puntatore potrebbe non essere stato creato da te ma dalla
classe A stessa.
Prova a pensare a questo caso:
La classe A definisce un meccanismo di allocazione/deallocazione locale (ovvero
ha operator new e operator delete come membri). Questo sistema gestisce la
memoria localmente e "sa" in ogni momento quali sono le A allocate. In altre
parole mantiene un puntatore a ciascuna A allocata per tutto il tempo in cui la
A resta "viva".
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

straordinario, ma qualche consiglio utile lo da.
appena avrò un po' di tempo e soldi...


 A resta "viva".
ci posso anche pensare, ma basta il codice che ti ho scritto qualche
riga fa per combinare casini, anche senza pensare a casi complessi
:o). Comunque quello che intendevo dire ad Antonio è che il codice era
corretto dal punto di vista della sintassi, ovvero che un compilatore
aderente allo standard lo avrebbe accettato senza battere ciglio.
E' naturale che ci sono tutta una serie di problemi a scrivere codice
che faccia questo genere di operazioni perchè quando usi un costrutto
a basso livello come i puntatori le rogne te le vai a cercare anche
senza scrivere il codice mirabolante visto in questo thread, ma se mi
parli di correttezza, senz'altro
#include <new>
#include <iostream>
class A
{
 int a_;
public:
 A( int a): a_( a) { }
};
int main()
{
    int a( 10);
    void * p = &a;
    A * pa = new( p) A( a);
    delete pa;
    std::cout << a;
    return 0;
}
è sintatticamente corretto. O sbaglio? (a me funziona anche :o))

 delete pa2;
Andrea Ferro


 evitare indipendentemente da cosa dice lo standard.
fammi capire, se devi allocare x byte lo fai su un heap, se ne devi
allocare y (con x != y) potrebbe succedere che siano allocati su un
altro heap? Ok, mi sembra abbastanza chiaro e anche ragionevole su
sistemi dove non esiste la memoria virtuale (ad esempio su DOS mi
sembra probabile un comportamento simile). Quello che non mi č chiaro
č: quando arriva alla delete il puntatore da ripulire, come fa a
sapere in quale heap era stato allocato, visto che non c'č un
parametro che mi dice quanto grande č il dato puntato da quel
puntatore? sě, beh, basterebbero delle tabelle... sě, effettivamente
potrebbe benissimo essere... comunque per tutto il resto del post non
posso che darti ragione, ma ammetterai che se si parlava di sintassi,
il codice che ha originato il dibattito era effettivamente corretto.

 il codice che ha originato il dibattito era effettivamente corretto.
Certo. Ma sintatticamente anche questo e' ok:
char *p1=new char[1];
char *p2=0;
delete [] p1;
p1[1]=p2[2]='!';
