Какая польза от деструктора как частного? - PullRequest
175 голосов
/ 10 марта 2009

Какая польза от деструктора как частного?

Ответы [ 9 ]

158 голосов
/ 10 марта 2009

По сути, всякий раз, когда вы хотите, чтобы какой-то другой класс отвечал за жизненный цикл объектов вашего класса, или у вас есть причина предотвратить уничтожение объекта, вы можете сделать деструктор приватным.

Например, если вы выполняете какие-то операции подсчета ссылок, вы можете поручить объекту (или менеджеру, который был «другом») отвечать за подсчет количества ссылок на себя и удалять его, когда число достигает нуль. Закрытый dtor не позволит кому-либо удалить его, если на него еще есть ссылки.

В другом случае, что если у вас есть объект, имеющий менеджера (или самого себя), который может уничтожить его или может отказаться уничтожить его в зависимости от других условий в программе, таких как открытое соединение с базой данных или файл написано. В классе или у менеджера может быть метод request_delete, который проверит это условие, удалит или отклонит его и вернет состояние, сообщающее, что он сделал. Это гораздо более гибко, чем просто вызывать «удалить».

64 голосов
/ 10 марта 2009

Такой объект никогда не может быть создан в стеке. Всегда в куче. И удаление должно быть сделано через друга или члена. Продукт может использовать единственную иерархию объектов и пользовательский менеджер памяти - в таких сценариях может использоваться личный 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;
}
44 голосов
/ 10 марта 2009

Когда вы не хотите, чтобы пользователи обращались к деструктору, т. Е. Вы хотите, чтобы объект был уничтожен только другими способами.

http://blogs.msdn.com/larryosterman/archive/2005/07/01/434684.aspx приводит пример, в котором объект имеет счетную ссылку и должен быть уничтожен только самим объектом, когда счетчик становится равным нулю.

16 голосов
/ 11 марта 2009

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

Вот пример того, как будет выглядеть метод Release.

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

ATL COM-объекты являются ярким примером этого шаблона.

8 голосов
/ 17 мая 2015

Добавление к ответам, уже присутствующим здесь; частные конструкторы и деструкторы весьма полезны при реализации фабрики , где созданные объекты должны размещаться в куче. Объекты, как правило, создаются / удаляются статическим членом или другом. Пример типичного использования:

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
}
6 голосов
/ 10 марта 2009

Класс может быть удален только сам по себе. Полезно, если вы создаете некоторый объект подсчета ссылок. Тогда только метод release может удалить объект, что, возможно, поможет вам избежать ошибок.

3 голосов
/ 10 марта 2011

прямо не так. Вот пример объекта с частным c-tor и d-tor, созданным в стеке (здесь я использую статическую функцию-член, но это также можно сделать с помощью функции Friend или класса Friend).

#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 голосов
/ 10 марта 2009

Я знаю, что вы спрашивали о частном деструкторе. Вот как я использую защищенные. Идея в том, что вы не хотите удалять основной класс через указатель на класс, который добавляет дополнительные функции к основному.
В примере ниже я не хочу, чтобы 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(){}
};
2 голосов
/ 10 марта 2009

Это может быть способ решения проблемы в Windows, где каждый модуль может использовать свою кучу, например, кучу Debug . Если эта проблема не решена правильно плохо вещи могут произойти.

...