Apa gunanya memiliki destructor sebagai pribadi?

194

Apa gunanya memiliki destructor sebagai pribadi?

yesraaj
sumber

Jawaban:

176

Pada dasarnya, setiap kali Anda ingin beberapa kelas lain bertanggung jawab atas siklus hidup objek kelas Anda, atau Anda memiliki alasan untuk mencegah penghancuran suatu objek, Anda dapat menjadikan destruktor itu pribadi.

Misalnya, jika Anda melakukan semacam penghitungan referensi, Anda dapat memiliki objek (atau pengelola yang "teman" red) yang bertanggung jawab untuk menghitung jumlah referensi itu sendiri dan menghapusnya ketika jumlahnya mencapai nol. Seorang dtor pribadi akan mencegah orang lain menghapusnya ketika masih ada referensi untuk itu.

Untuk contoh lain, bagaimana jika Anda memiliki objek yang memiliki manajer (atau dirinya sendiri) yang dapat menghancurkannya atau mungkin menolak untuk menghancurkannya tergantung pada kondisi lain dalam program, seperti koneksi database yang terbuka atau file yang sedang ditulis. Anda bisa memiliki metode "request_delete" di kelas atau manajer yang akan memeriksa kondisi itu dan itu akan menghapus atau menolak, dan mengembalikan status yang memberi tahu Anda apa yang telah dilakukannya. Itu jauh lebih fleksibel daripada hanya memanggil "hapus".

Paul Tomblin
sumber
73

Objek seperti itu tidak pernah dapat dibuat di stack. Selalu di tumpukan. Dan penghapusan harus dilakukan melalui teman atau anggota. Suatu produk dapat menggunakan hierarki objek tunggal dan manajer memori khusus - skenario tersebut dapat menggunakan dtor pribadi.

#include <iostream>
class a {
    ~a() {}
    friend void delete_a(a* p);
};


void delete_a(a* p)  {
    delete p;
}

int main()
{
    a *p = new a;
    delete_a(p);

    return 0;
}
secara langsung
sumber
19
Koreksi: Objek seperti itu dapat dibuat di stack (tetapi hanya dalam lingkup teman atau dirinya sendiri).
Thomas Eding
Selain itu tidak dapat ba objek statis atau global (yaitu, memiliki "durasi penyimpanan statis") dalam implementasi yang di-host (karena destruktor akan dipanggil pada saat keluar dari program).
Peter - Reinstate Monica
17

COM menggunakan strategi ini untuk menghapus instance. COM menjadikan destructor sebagai pribadi dan menyediakan antarmuka untuk menghapus instance.

Berikut ini adalah contoh dari bagaimana metode Release akan terlihat.

int MyRefCountedObject::Release() 
{
 _refCount--;
 if ( 0 == _refCount ) 
 {
    delete this;
    return 0;
 }
 return _refCount;
}

Objek ATL COM adalah contoh utama dari pola ini.

Vinay
sumber
8

Menambah jawaban sudah ada di sini; konstruktor dan destruktor pribadi cukup berguna saat menerapkan pabrik di mana objek yang dibuat harus dialokasikan pada heap. Objek akan, secara umum, dibuat / dihapus oleh anggota statis atau teman. Contoh penggunaan tipikal:

class myclass
{
public:
    static myclass* create(/* args */)  // Factory
    {
        return new myclass(/* args */);
    }

    static void destroy(myclass* ptr)
    {
        delete ptr;
    }
private:
    myclass(/* args */) { ... }         // Private CTOR and DTOR
    ~myclass() { ... }                  // 
}

int main ()
{
    myclass m;                          // error: ctor and dtor are private
    myclass* mp = new myclass (..);     // error: private ctor
    myclass* mp = myclass::create(..);  // OK
    delete mp;                          // error: private dtor
    myclass::destroy(mp);               // OK
}
nav
sumber
7

Kelas hanya dapat dihapus dengan sendirinya. Berguna jika Anda membuat beberapa percobaan referensi objek yang dihitung. Maka hanya metode pelepasan yang dapat menghapus objek, mungkin membantu Anda menghindari kesalahan.

Roland Rabien
sumber
3

Saya tahu Anda bertanya tentang destruktor pribadi. Inilah cara saya menggunakan yang dilindungi. Idenya adalah Anda tidak ingin menghapus kelas utama melalui pointer ke kelas yang menambahkan fungsionalitas tambahan ke utama.
Dalam contoh di bawah ini saya tidak ingin GuiWindow dihapus melalui pointer HandlerHolder.

class Handler
{
public:
    virtual void onClose() = 0;
protected:
    virtual ~Handler();
};

class HandlerHolder
{
public:
    void setHandler( Handler* );
    Handler* getHandler() const;
protected:
    ~HandlerHolder(){}
private:
    Handler* handler_;
};

class GuiWindow : public HandlerHolder
{
public:
    void finish()
    {
        getHandler()->onClose();
    }

    virtual ~GuiWindow(){}
};
Mykola Golubyev
sumber
3

dirkgently salah. Berikut adalah contoh objek dengan private c-tor dan d-tor yang dibuat pada stack (Saya menggunakan fungsi anggota statis di sini, tetapi dapat dilakukan dengan fungsi teman atau kelas teman juga).

#include <iostream>

class PrivateCD
{
private:
    PrivateCD(int i) : _i(i) {};
    ~PrivateCD(){};
    int _i;
public:
    static void TryMe(int i)
    {
        PrivateCD p(i);
        cout << "inside PrivateCD::TryMe, p._i = " << p._i << endl;
    };
};

int main()
{
    PrivateCD::TryMe(8);
};

Kode ini akan menghasilkan keluaran: di dalam PrivateCD :: TryMe, p._i = 8

misicd
sumber
3
Saya cukup yakin secara langsung berarti bahwa kode yang menggunakan kelas Anda tidak dapat membuat instance kelas pada stack. Tentu saja Anda masih dapat membuat instance kelas pada stack dalam metode kelas, karena dalam konteks itu Anda dapat mengakses memebers pribadi.
Edward Loper
2

Mungkin cara untuk mengatasi masalah di Windows di mana setiap modul dapat menggunakan tumpukan yang berbeda, seperti tumpukan Debug . Jika masalah itu tidak ditangani dengan benar, hal - hal buruk dapat terjadi.

Jared Oberhaus
sumber