TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #903 4.43K
​​Недостатки std::make_shared. Деаллокация
#новичкам

Представляете, забыл выложить один важный пост из серии про недостатки std::make_shared. Затерялся он в пучине заметок. Исправляюсь.

В предыдущих сериях:
Кастомный new и delete
Непубличные конструкторы
Кастомные делитеры

А теперь поговорим про деаллокацию.

В этом посте мы рассказали о том, что std::make_shared выделяет один блок памяти под объект и контрольный блок. 1 аллокация вместо 2-х = большая производительность. Однако у монеты всегда две стороны.

Что происходит с объектом и памятью при работе с shared_ptr напрямую через конструктор?


Отдельно выделяется память и конструируется разделяемый объект с помощью явного вызова new, отдельно выделяется память и конструируется контрольный блок.

Деструктор разделяемого объекта и освобождение памяти для него происходит ровно в тот момент, когда счетчик сильных ссылок становится нулем. При этом контрольный блок остается живым до момента уничтожения последнего std::weak_ptr:

void operator delete(void *ptr) noexcept {
std::cout << "Global delete " << std::endl;
std::free(ptr);
}

class MyClass {
public:
~MyClass() {
std::cout << "Деструктор MyClass вызван.\n";
}
};

int main() {
std::weak_ptr<MyClass> weak;

{
std::shared_ptr<MyClass> shared(new MyClass());
weak = shared;
std::cout
<< "shared_ptr goes out of scope...\n";
} // Here shared is deleting

std::cout << "weak.expired(): " << weak.expired()
<< '\n';
weak.reset();

std::cout << "All memory has been freed!\n";
}
// OUTPUT:
// shared_ptr goes out of scope...
// Dtor MyClass called.
// Global delete
// weak.expired(): 1
// Global delete
// All memory has been freed!


Мы переопределили глобальный delete, чтобы увидеть момент освобождения памяти на разных этапах.

Деструктор и delete для разделяемого объекта вызываются ровно в момент выхода объекта shared из своего скоупа. Тем не менее weak_ptr жив, он знает, что объекта уже нет, но своим наличием продлевает время жизни контрольного блока. После ресета weak ожидаемо происходит деаллокация блока.

Что же происходит при использовании std::make_shared? В какой момент освобождается вся выделенная память?

Только когда оба счетчика сильных и слабых ссылок будут равны нулю. То есть не осталось ни одного объекта std::shared_ptr и std::weak_ptr, которые указывают на объект. Тем не менее семантически разделяемый объект уничтожается при разрушении последней сильной ссылки:

void operator delete(void *ptr) noexcept {
std::cout << "Global delete " << std::endl;
std::free(ptr);
}

class MyClass {
public:
~MyClass() {
std::cout << "Деструктор MyClass вызван.\n";
}
};
int main() {
std::weak_ptr<MyClass> weak;

{
auto shared = std::make_shared<MyClass>();
weak = shared;

std::cout << "shared_ptr goes out of scope...\n";
} // shared уничтожается здесь

std::cout << "weak.expired(): " << weak.expired()
<< '\n'; // true
weak.reset();

std::cout << "All memory has been freed!\n";
}
// shared_ptr goes out of scope...
// Dtor MyClass called.
// weak.expired(): 1
// Global delete
// All memory has been freed!


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

Учитывайте эти особенности, когда используете weak_ptr(например в кэше или списках слушателей).

Consider both sides of the coin. Stay cool.

#cpp11 #memory
  • 🔥 18
  • 👍 11
  • ❤ 7
  • ❤‍🔥 3
  • 😁 1
More from @grokaemcpp
  1. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  2. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  3. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  4. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  5. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  6. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
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 →