Domanda

Ho un class A che utilizza un'allocazione di memoria heap per uno dei suoi campi. Classe A viene istanziato e memorizzato come un campo puntatore in un'altra classe (class B.

Quando ho finito con un oggetto della classe B, che io chiamo delete, che presumo chiamate il distruttore ... Ma questo lo chiamo il distruttore di classe A come bene?

Modifica:

Dalle risposte, ho Take That (si prega di modificare, se non corretta):

  1. A::~A(); di un'istanza di B chiama B :: ~ B ();
  2. che chiama A::~A
  3. <=> dovrebbe <=> esplicitamente tutte le variabili utente heap allocata del Un oggetto;
  4. Infine la memorizzazione blocco di memoria detta istanza di classe B è restituito al mucchio - quando nuovo è stato utilizzato, in primo luogo assegnato un blocco di memoria sul mucchio, quindi invocato costruttori per inizializzare, ora dopo tutti i distruttori sono state invocate per finalizzare l'oggetto del blocco in cui l'oggetto risiedeva viene restituito al mucchio.
È stato utile?

Soluzione

Il distruttore di A sarà eseguito quando la sua vita è finita. Se si desidera che la sua memoria da liberare e la corsa distruttore, bisogna eliminarlo se è stato allocato sul mucchio. Se è stato allocato sullo stack questo avviene automaticamente (vale a dire quando si passa nell'ambito, vedi Raii). Se è un membro di una classe (non un puntatore, ma un membro a pieno), allora questo avverrà quando l'oggetto contenitore viene distrutto.

class A
{
    char *someHeapMemory;
public:
    A() : someHeapMemory(new char[1000]) {}
    ~A() { delete[] someHeapMemory; }
};

class B
{
    A* APtr;
public:
    B() : APtr(new A()) {}
    ~B() { delete APtr; }
};

class C
{
    A Amember;
public:
    C() : Amember() {}
    ~C() {} // A is freed / destructed automatically.
};

int main()
{
    B* BPtr = new B();
    delete BPtr; // Calls ~B() which calls ~A() 
    C *CPtr = new C();
    delete CPtr;
    B b;
    C c;
} // b and c are freed/destructed automatically

Nell'esempio precedente, ogni eliminare e delete [] è necessario. E nessuna cancellazione è necessario (o effettivamente in grado di essere utilizzato) dove io non lo uso.

auto_ptr, unique_ptr e shared_ptr ecc ... sono grande per fare questa gestione vita molto più semplice:

class A
{
    shared_array<char> someHeapMemory;
public:
    A() : someHeapMemory(new char[1000]) {}
    ~A() { } // someHeapMemory is delete[]d automatically
};

class B
{
    shared_ptr<A> APtr;
public:
    B() : APtr(new A()) {}
    ~B() {  } // APtr is deleted automatically
};

int main()
{
    shared_ptr<B> BPtr = new B();
} // BPtr is deleted automatically

Altri suggerimenti

Quando si chiama eliminare su un puntatore assegnato dal nuovo, il distruttore dell'oggetto puntato sarà chiamato.

A * p = new A;

delete p;    // A:~A() called for you on obkect pointed to by p

Si chiama "distruttore", non "decostruttore".

All'interno il distruttore di ogni classe, è necessario eliminare tutte le altre variabili membro che sono state assegnate con il nuovo.

Modifica: Per chiarire:

Diciamo che avete

struct A {}

class B {
    A *a;
public:
    B () : a (new A) {}
    ~B() { delete a; }
};

class C {
    A *a;
public:
    C () : a (new A) {}        
};

int main () {
    delete new B;
    delete new C;
}

L'assegnazione di un'istanza di B e quindi eliminando è pulito, perché ciò B alloca internamente verranno eliminati anche nel distruttore.

Ma istanze della classe C coleranno memoria, perché alloca un'istanza di A che non emette (in questo caso C non ha nemmeno un distruttore).

Se si dispone di un puntatore al solito (A*) allora il distruttore non sarà chiamato (e memoria per A esempio, non sarà liberato o) a meno che non delete esplicitamente distruttore B s '. Se si desidera guardare la distruzione automatica a puntatori intelligenti come auto_ptr.

Si dovrebbe eliminare un te stesso nel distruttore di B.

class B
{
public:
    B()
    {
       p = new int[1024];  
    }
    virtual ~B()
    {
        cout<<"B destructor"<<endl;
        //p will not be deleted EVER unless you do it manually.
    }
    int *p;
};


class D : public B
{
public:
    virtual ~D()
    {
        cout<<"D destructor"<<endl;
    }
};

Quando si esegue:

B *pD = new D();
delete pD;

Il distruttore viene chiamato solo se la classe di base ha la parola chiave virtuale.

Quindi se non si dispone di un distruttore virtuale solo ~ B () sarebbe chiamato. Ma dal momento che si dispone di un distruttore virtuale, prima ~ D () sarà chiamato, quindi ~ B ().

Non ci sono membri di B o D allocato sul mucchio saranno deallocate a meno che non vengano eliminati in modo esplicito. E di cancellarli chiamerà il loro distruttore pure.

Mi chiedevo perché la mia classe distruttore non è stato chiamato. Il motivo era che avevo dimenticato di includere la definizione di quella classe ( "class.h" # include). Ho avuto solo una dichiarazione del tipo "classe A"; e il compilatore è stata felice con lui e mi ha lasciato chiamo "Cancella".

No. il puntatore sarà cancellato. Si dovrebbe chiamare l'eliminazione di un esplicito nel distruttore di B.

Il distruttore per l'oggetto della classe A sarà chiamato solo se eliminazione viene chiamato per quell'oggetto. Assicurati di eliminare tale puntatore nel distruttore della classe B.

Per un po 'più di informazioni su ciò che accade quando di eliminazione viene chiamato su un oggetto, vedere: http://www.parashift.com/c++- faq-lite / Freestore-mgmt.html # faq-16.9

No, non chiamerà distruttore per la classe A, si dovrebbe chiamare in modo esplicito (come PoweRoy detto), cancellare la linea 'delete ptr;' nell'esempio per confrontare ...

  #include <iostream>

  class A
  {
     public:
        A(){};
        ~A();
  };

  A::~A()
  {
     std::cout << "Destructor of A" << std::endl;
  }

  class B
  {
     public:
        B(){ptr = new A();};
        ~B();
     private:
        A* ptr;
  };

  B::~B()
  {
     delete ptr;
     std::cout << "Destructor of B" << std::endl;
  }

  int main()
  {
     B* b = new B();
     delete b;
     return 0;
  }

Hai qualcosa di simile

class B
{
   A * a;
}
B * b = new B;
b->a = new A;

Se quindi si chiama delete b;, non succede nulla a una, e si dispone di una perdita di memoria. Cercando di ricordare a delete b->a; non è una buona soluzione, ma ci sono un paio di altri.

B::~B() {delete a;}

Questo è un distruttore per B che cancellerà a. (Se a è 0, che cancella non fa nulla. Se una non è 0, ma non punta a memoria dal nuovo, si ottiene il danneggiamento di heap.)

auto_ptr<A> a;
...
b->a.reset(new A);

In questo modo non si dispone di un come un puntatore, ma piuttosto un auto_ptr <> (shared_ptr <> farà così, o altri puntatori intelligenti), e viene eliminato automaticamente quando b è.

Uno di questi modi funziona bene, e ho usato entrambe le cose.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top