TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #421 4.72K
​​Зачем может понадобиться делать деструктор приватным?
#новичкам

Недавно мы узнали, что можно делать деструктор приватным. Те, кто не слышал о этой технике, скорее всего подумали: "Сомнительно........но.....окэй". Потому что с первого взгляда не очень понятно, для чего вообще нужно заниматься этими непристойностями in the first place. Чтобы запретить пользователю создавать объекты на стеке и в статической области?

Ну и действительно, этот паттерн используется нечасто. Однако кейсы применения все же есть.

Один из основных - ATL COM объекты. Их цикл жизни регулируется с помощью подсчета ссылок. И чтобы никто не смог удалить объект, на который все еще ссылаются ссылки, для объектов вводят приватный деструктор и метод Release. В нем происходит декремент ссылки, проверка их количества и удаление объекта, если он остался больше никому не нужным. Выглядеть это может примерно так:

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


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

Помимо этого примера, для меня вообще довольно странная история, чтобы позволять какому-то коду создавать объект, но не позволять удалять его. Если я бы захотел контролировать удаление объекта, то с вероятностью 99% я бы захотел контролировать его создание. Чтобы так сказать стать черным властелином его цикла жизни. Поэтому, на мой взгляд, приватный деструктор должен идти вместе с приватным конструктором.

Для синглтонов имеет смысл сделать деструктор приватным, чтобы никто по ошибке не смог явно вызвать на ссылке деструктор. Сам деструктор вызывается в статическом методе-геттере, который имеет доступ к приватным полям, тут все аккуратно работает.

Также приватные конструктор и деструктор могут идти в комплекте с двумя статическими методами: Create() и Destroy().

Например, из Create возвращать умный указатель и указывать в качестве его делитера приватный статический метод Destroy. Таким образом вы можете реализовать довольно сложную логику создания и удаления объекта. Когда, например, у вас есть конструктор и метод init, то для ограничения работы с созданным, но не инициализированным объектом, используется статический метод Create. По аналогии для деструктора и finalize мы используем Destroy. Мы никого не ограничиваем в правильном создании и удалении объектов. Просто хотим, чтобы только через эти два метода проходило создание и удаление объектов.

class ControlLifeCycle
{
public:
static std::unique_ptr<ControlLifeCycle, void()(ControlLifeCycle)> Create() // Factory
{
auto deleter = [](ControlLifeCycle * obj)
{
ControlLifeCycle::Destroy(obj);
};
std::cout << "I was born!" << std::endl;
return std::unique_ptr<ControlLifeCycle, decltype(deleter)>(new ControlLifeCycle, deleter);
}
private:
static void Destroy(ControlLifeCycle* ptr)
{
std::cout << "I've been destroyed!" << std::endl;
delete ptr;
}
ControlLifeCycle() {} // Private CTOR and DTOR
~ControlLifeCycle() {}
};

ControlLifeCycle global_var; // error: ctor and dtor are private

int main ()
{
ControlLifeCycle stack_var; // error: ctor and dtor are private
ControlLifeCycle* dynamic_var = new ControlLifeCycle; // error: private ctor
auto smart_var = ControlLifeCycle::Create(); // OK
}


Можно из метода Create возвращать просто указатель и оставить метод Destroy публичным. Тогда только мы своими очумелыми ручками сможем напечатать в нужном месте кода "Class::Destroy(ptr);" и только тогда произойдет освобождение ресурсов и ни в каком другом случае.

В общем, эта техника может использоваться в любом месте, где нам необходим полный контроль над циклом жизни объекта и над способом его рождения и захоронения.

Control cycle of your life. Stay cool.
  • ❤ 16
  • 👍 10
  • 🔥 6
  • ⚡ 2
More from @grokaemcpp
  1. Oct 14, 2026​​Что внутри std::condition_variable? #опытным Более менее все знакомы с примитивом синхро…
  2. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  3. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  4. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  5. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  6. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →