Яка користь від деструктора як приватного?


Відповіді:


177

В основному, коли ви хочете, щоб якийсь інший клас відповідав за життєвий цикл об'єктів вашого класу, або у вас є підстави запобігти знищенню об'єкта, ви можете зробити деструктор приватним.

Наприклад, якщо ви робите якусь річ підрахунку посилань, ви можете покласти на об'єкт (або менеджер, який був "другом"), відповідальний за підрахунок кількості посилань на себе та видалити його, коли число досягне нуля. Приватний dtor заважав би комусь іншого видалити його, коли на нього ще були посилання.

Для іншого випадку, що робити, якщо у вас є об'єкт, у якого є менеджер (або сам), який може його знищити або може відмовити його знищити залежно від інших умов програми, наприклад, відкрите підключення до бази даних або записаний файл. У вас може бути метод "request_delete" в класі або менеджер, який перевірить цю умову, і він або видалить, або відхилить, і поверне статус, який розповість вам, що він зробив. Це набагато гнучкіше, ніж просто виклик "видалити".


73

Такий об’єкт ніколи не можна створити на стеці. Завжди на купі. І видалення потрібно робити через друга або члена. Продукт може використовувати одну ієрархію об'єктів і спеціальний менеджер пам'яті - такі сценарії можуть використовувати приватний dtor.

#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;
}

19
Виправлення: такий об’єкт можна створити на стеці (але лише в межах друга чи самого себе).
Томас Едінг

Крім того, він не може базувати статичний або глобальний об'єкт (тобто мати "статичну тривалість зберігання") в розміщеній реалізації (тому що деструктор буде викликаний при виході програми).
Пітер - Відновіть Моніку

45

Якщо ви не хочете, щоб користувачі отримували доступ до деструктора, тобто ви хочете знищити об'єкт лише іншими засобами.

http://blogs.msdn.com/larryosterman/archive/2005/07/01/434684.aspx наводить приклад, коли об’єкт посилається на облік і його слід знищувати сам об’єкт, коли кількість переходить до нуля.


17

COM використовує цю стратегію для видалення екземпляра. COM робить деструктор приватним і надає інтерфейс для видалення екземпляра.

Ось приклад того, як виглядатиме метод Release.

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

Об'єкти ATL COM є яскравим прикладом цієї моделі.


8

Додавання до вже наявних відповідей; приватні конструктори та деструктори є досить корисними при впровадженні на заводі, де створені об'єкти потрібно виділити на купу. Об'єкти, як правило, були створені / видалені статичним членом або другом. Приклад типового використання:

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
}

7

Клас можна видалити лише сам. Корисно, якщо ви створюєте деякий спробу посилального рахунку об'єкта. Тоді лише метод випуску може видалити об'єкт, можливо, допоможе вам уникнути помилок.


3

Я знаю, що ви питали про приватного деструктора. Ось як я використовую захищені. Ідея полягає в тому, що ви не хочете видаляти головний клас через покажчик на клас, який додає додатковій функціональності до основного.
У наведеному нижче прикладі я не хочу видаляти GuiWindow через покажчик 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(){}
};

3

грязно помиляється. Ось приклад об’єкта з приватними c-tor та d-tor, створеними в стеці (я тут використовую статичну функцію члена, але це також можна зробити з функцією friend або friend class).

#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);
};

Цей код дасть вихід: всередині PrivateCD :: TryMe, p._i = 8


3
Я майже впевнений, що немилосердно мається на увазі, що код, який використовує ваш клас, не може створювати клас у стеці. Звичайно, ви все ще можете інстанціювати клас на стеці в межах методів класу, оскільки в цьому контексті ви можете отримати доступ до приватних пам'яток.
Едвард Лопер

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.