26 августа 2021

πŸ›  Π£ΠΌΠ½Ρ‹Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π² C++

UE4 C++ Developer. Currently working with Flying Wild Hog on the Space Punks title. Author of articles on C++, GameDev, Unreal Engine and general programming
Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΎΠ± ΡƒΠΌΠ½Ρ‹Ρ… указатСлях Π² C++, Π·Π°Ρ‡Π΅ΠΌ ΠΎΠ½ΠΈ Π½ΡƒΠΆΠ½Ρ‹, Ρ‡Π΅ΠΌ Ρ€Π°Π·Π»ΠΈΡ‡Π°ΡŽΡ‚ΡΡ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ owning ΠΈ non-owning ΠΈ ΠΏΠΎΡ‡Π΅ΠΌΡƒ нСльзя всСгда ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ new/delete для создания ΠΈ удалСния ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ².
πŸ›  Π£ΠΌΠ½Ρ‹Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π² C++

Как C++ управляСт ΠΏΠ°ΠΌΡΡ‚ΡŒΡŽ?

ΠŸΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ ΠΎΠ±ΡŠΡΡΠ½ΠΈΡ‚ΡŒ, Π·Π°Ρ‡Π΅ΠΌ Π½ΡƒΠΆΠ½Ρ‹ ΠΈ ΠΊΠ°ΠΊΠΈΠ΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ Ρ€Π΅ΡˆΠ°ΡŽΡ‚ ΡƒΠΌΠ½Ρ‹Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ, ΠΌΡ‹ ΠΊΡ€Π°Ρ‚ΠΊΠΎ опишСм Ρ‚ΠΎ, ΠΊΠ°ΠΊ C++ управляСт ΠΏΠ°ΠΌΡΡ‚ΡŒΡŽ.

Когда ΠΌΡ‹ Π³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΏΡ€ΠΎ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠ°ΠΌΡΡ‚ΡŒΡŽ Π² C++, ΠΌΡ‹ Π½Π΅ΠΈΠ·ΠΌΠ΅Π½Π½ΠΎ обращаСмся ΠΊ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Ρƒ storage duration (Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ хранСния). Storage duration – это свойство ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ описываСт, ΠΊΠΎΠ³Π΄Π° Ρ‚ΠΎΡ‚ ΠΏΠΎΠΏΠ°Π΄Π°Π΅Ρ‚ Π² ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΈ ΠΊΠΎΠ³Π΄Π° Π΅Ρ‘ освобоТдаСт.

Π’ C++ сущСствуСт Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ Π²ΠΈΠ΄Π° [1] storage duration:

  • АвтоматичСская storage duration. Когда ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π²Ρ…ΠΎΠ΄ΠΈΡ‚ Π² ΠΎΠ±Π»Π°ΡΡ‚ΡŒ видимости ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° (Ρ‚Π°ΠΊΠΆΠ΅ ΠΈΠ·Π²Π΅ΡΡ‚Π½ΡƒΡŽ ΠΊΠ°ΠΊ scope [2]), ΠΎΠ½ размСщаСтся Π² автоматичСской памяти, Π·Π°Ρ‡Π°ΡΡ‚ΡƒΡŽ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠΉ Π² Π²ΠΈΠ΄Π΅ стСка; ΠΊΠΎΠ³Π΄Π° ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΠΊΠΈΠ΄Π°Π΅Ρ‚ эту ΠΎΠ±Π»Π°ΡΡ‚ΡŒ, вызываСтся дСструктор ΠΈ ΠΏΠ°ΠΌΡΡ‚ΡŒ освобоТдаСтся.
Листинг 1
        //ΠŸΠΎΠ΄ΠΎΠΏΡ‹Ρ‚Π½Ρ‹ΠΉ класс, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π½Π° протяТСнии всСй ΡΡ‚Π°Ρ‚ΡŒΠΈ
class X {
    int a;
    double b;
public:
    void func() {};
};
int main() {
    X object; //Π’ памяти создаСтся ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ класса X
    {
        X object2; //Π•Ρ‰Ρ‘ ΠΎΠ΄ΠΈΠ½ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Ρ€Π°Π·ΠΌΠ΅Ρ‰Ρ‘Π½ Π² памяти
        //Π’ Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π² памяти Ρ€Π°Π·ΠΌΠ΅Ρ‰Π΅Π½Ρ‹ ΠΈ доступны ΠΎΠ±Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°
    } //Π—Π΄Π΅ΡΡŒ object2 Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΈΠ· области видимости ΠΈ уничтоТаСтся
} //Π—Π΄Π΅ΡΡŒ уничтоТаСтся object
    
  • БтатичСская связана с использованиСм спСцификаторов static ΠΈ extern. ΠžΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ со статичСской storage duration ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ ΠΏΡ€ΠΈ запускС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΈ ΡƒΠ΄Π°Π»ΡΡŽΡ‚ΡΡ ΠΏΡ€ΠΈ Π΅Ρ‘ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠΈ.
  • Storage duration ΠΏΠΎΡ‚ΠΎΠΊΠ° устанавливаСтся спСцификатором thread_local. Π˜ΠΌΠ΅ΡŽΡ‰ΠΈΠ΅ эту storage duration ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ ΠΏΡ€ΠΈ стартС ΠΏΠΎΡ‚ΠΎΠΊΠ° ΠΈ ΡƒΠ΄Π°Π»ΡΡŽΡ‚ΡΡ ΠΏΡ€ΠΈ Π΅Π³ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠΈ.
  • ДинамичСская storage duration Π½Π΅Ρ€Π°Π·Ρ€Ρ‹Π²Π½ΠΎ связана с использованиСм ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹Ρ… слов new ΠΈ delete.
Листинг 2
        X* ptr = nullptr; //Π£ΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ, Π½Π΅ ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉ Π½ΠΈ Π½Π° Ρ‡Ρ‚ΠΎ
{
    X* ptr2 = new X(); //Π Π°Π·ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° класса X Π² памяти (Ρ‚Π°ΠΊΠΆΠ΅ извСстной ΠΊΠ°ΠΊ динамичСская ΠΏΠ°ΠΌΡΡ‚ΡŒ, Π·Π°Ρ‡Π°ΡΡ‚ΡƒΡŽ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠΉ Π² Π²ΠΈΠ΄Π΅ ΠΊΡƒΡ‡ΠΈ). ptr2 - ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° этот ΠΎΠ±ΡŠΠ΅ΠΊΡ‚
    ptr = ptr2; //ptr ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Π½Π° Ρ‚ΠΎΡ‚ ΠΆΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚
} //Π£ΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ ptr2 Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΈΠ· области видимости ΠΈ уничтоТаСтся, Π½ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΎΠ½ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚, остаётся Π² памяти
delete ptr; //ΠŸΡ€ΠΎΠΈΡΡ…ΠΎΠ΄ΠΈΡ‚ Π²Ρ‹Π·ΠΎΠ² дСструктора, Π° послС этого ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ ptr, удаляСтся ΠΈΠ· памяти
    

МоТно ΡΠΊΠ°Π·Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Π² случаС с автоматичСской storage duration ΠΏΠ°ΠΌΡΡ‚ΡŒ освобоТдаСтся автоматичСски, Π° Π² случаС с динамичСской – Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ. ΠŸΠΎΡ‡Π΅ΠΌΡƒ ΠΆΠ΅ Ρ‚ΠΎΠ³Π΄Π° Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ всСгда Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ ΠΏΠ°ΠΌΡΡ‚ΡŒ?

  • Π§Ρ‚ΠΎΠ±Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ стСк, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π·Π°Ρ€Π°Π½Π΅Π΅ Π½Π° этапС компиляции Π·Π½Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΠΌΠ½ΠΎΠ³ΠΎ памяти понадобится, Π° это извСстно Π½Π΅ всСгда.
  • Иногда Π½Π°Π΄ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ оставался Π² памяти ΠΈ послС Π²Ρ‹Ρ…ΠΎΠ΄Π° ΠΈΠ· области видимости Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π±Ρ‹Π» создан, Π° Π² случаС размСщСния ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π½Π° стСкС это Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ.

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ±ΠΎΠΉΡ‚ΠΈ эти ограничСния, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡Π΅ΡΠΊΡƒΡŽ ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΏΡ€ΠΎ использованиС ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΌΡ‹ ΠΈ Π±ΡƒΠ΄Π΅ΠΌ сСгодня Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ΡŒ.

Π§Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ ΡƒΠΌΠ½Ρ‹Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ ΠΈ Π·Π°Ρ‡Π΅ΠΌ ΠΎΠ½ΠΈ Π½ΡƒΠΆΠ½Ρ‹?

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡Π΅ΡΠΊΡƒΡŽ ΠΏΠ°ΠΌΡΡ‚ΡŒ, ΠΎΡ‚Π»ΠΈΡ‡Π½ΠΎ. Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΠΌΠΎΠ³ΡƒΡ‚ ΠΏΠΎΠΊΠΈΠ΄Π°Ρ‚ΡŒ ΠΎΠ±Π»Π°ΡΡ‚ΡŒ видимости, Π³Π΄Π΅ Π±Ρ‹Π»ΠΈ созданы, ΠΈ ΠΈΠΌΠ΅Ρ‚ΡŒ опрСдСляСмый Π²ΠΎ врСмя выполнСния Ρ€Π°Π·ΠΌΠ΅Ρ€ – Тизнь стала Π½Π°Π»Π°ΠΆΠΈΠ²Π°Ρ‚ΡŒΡΡ ΠΈ ΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΊΠ°ΠΊ Π±ΡƒΠ΄Ρ‚ΠΎ Π½Π΅ Π½Π° Ρ‡Ρ‚ΠΎ.

ΠŸΡ€Π΅Π΄Π»Π°Π³Π°Π΅ΠΌ Π²Π·Π³Π»ΡΠ½ΡƒΡ‚ΡŒ Π½Π° ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ ΠΊΠΎΠ΄Π°:

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅
ВсС ΡƒΠΌΠ½Ρ‹Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ доступны Ρ‡Π΅Ρ€Π΅Π· Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ Ρ…Π΅Π΄Π΅Ρ€Π° (#include <memory>). Для краткости Π²ΠΎ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π°Ρ… ΠΊΠΎΠ΄Π° Π²Π½ΡƒΡ‚Ρ€ΠΈ ΡΡ‚Π°Ρ‚ΡŒΠΈ это Π±Ρ‹Π»ΠΎ ΠΎΠΏΡƒΡ‰Π΅Π½ΠΎ.
Листинг 3
        X* ptr = new X();
if (func()) {
    func2();
    return;
}
delete ptr;
    

На ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ взгляд, здСсь всё Ρ…ΠΎΡ€ΠΎΡˆΠΎ, Π½ΠΎ Π΅ΡΡ‚ΡŒ Π½ΡŽΠ°Π½ΡΡ‹:

  • Если func() выбросит ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅, Ρ‚ΠΎ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π΅ Π΄ΠΎΠΉΠ΄Ρ‘Ρ‚ Π΄ΠΎ delete ΠΈ ΠΏΠ°ΠΌΡΡ‚ΡŒ Π½Π΅ освободится.
  • Если func() Π²Π΅Ρ€Π½Ρ‘Ρ‚ true, Ρ‚ΠΎ послС выполнСния func2() ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΠΊΠΈΠ½Π΅Ρ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, Π½ΠΎ ΠΏΠ°ΠΌΡΡ‚ΡŒ Π½Π΅ освободится, Ρ‚.ΠΊ. Π°Π²Ρ‚ΠΎΡ€ ΠΊΠΎΠ΄Π° Π·Π°Π±Ρ‹Π» Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ delete Π²Π½ΡƒΡ‚Ρ€ΡŒ условия.
  • Если Π±Ρ‹ Π°Π²Ρ‚ΠΎΡ€ Π·Π°Π±Ρ‹Π» delete Ρ‚Π°ΠΊΠΆΠ΅ Π² 6-ΠΉ строкС, ΠΏΠ°ΠΌΡΡ‚ΡŒ Ρ‚ΠΎΠΆΠ΅ Π½Π΅ освободилась Π±Ρ‹.
Π’ΡƒΡ‚ C++ программисты Ρ€Π΅ΡˆΠΈΠ»ΠΈ, Ρ‡Ρ‚ΠΎ с Π½ΠΈΡ… Ρ…Π²Π°Ρ‚ΠΈΡ‚, ΠΈ ΠΏΡ€ΠΈΠ΄ΡƒΠΌΠ°Π»ΠΈ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ, Π·Π°ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‰Π΅Π΅ΡΡ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ new/delete. Как – ΡƒΠ²ΠΈΠ΄ΠΈΠΌ Π½ΠΈΠΆΠ΅.

Помимо ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ нСпосрСдствСнно с new/delete, сущСствуСт ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° ΠΈ с простыми указатСлями. Она Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² слоТности раздСлСния ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π²Π»Π°Π΄Π΅ΡŽΡ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ (owning pointer), Π° Π·Π½Π°Ρ‡ΠΈΡ‚, ΠΈ отвСтствСнны Π·Π° Π²Ρ‹Π·ΠΎΠ² new/delete, ΠΈ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ (non owning pointer).

ΠŸΡ€ΠΈ использованиС простых ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΉ (Ρ‚Π°ΠΊΠΆΠ΅ извСстных ΠΊΠ°ΠΊ raw pointers) Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ Π±Π΅Π· Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠ΅Π² ΠΈΠ»ΠΈ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ изучСния ΠΊΠΎΠ΄Π° ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ, ΠΊΠ°ΠΊΠΎΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ Π²Π»Π°Π΄Π΅Π΅Ρ‚, Π° ΠΊΠ°ΠΊΠΎΠΉ – Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚. ВзглянитС Π½Π° ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΡƒΡŽ Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ†ΠΈΡŽ:

Листинг 4
        int* func();
    

Главная ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° здСсь, Ρ‡Ρ‚ΠΎ Ρ‚ΠΎΠΌΡƒ, ΠΊΡ‚ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, ΡΠΎΠ²Π΅Ρ€ΡˆΠ΅Π½Π½ΠΎ нСясно, Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΎΠ½ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ delete для Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΠΎΠ³ΠΎ указатСля ΠΈΠ»ΠΈ Π·Π° это отвСтствСнСн ΠΊΠΎΠ΄ Π³Π΄Π΅-Ρ‚ΠΎ Π² Π΄Ρ€ΡƒΠ³ΠΎΠΉ части ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹. Π˜Π½Π°Ρ‡Π΅ говоря, здСсь Π½Π΅ Π²ΠΈΠ΄Π½ΠΎ, являСтся ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π²Π»Π°Π΄Π΅ΡŽΡ‰ΠΈΠΌ ΠΈΠ»ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠΌ.

ВсС Π²Ρ‹ΡˆΠ΅Π½Π°Π·Π²Π°Π½Π½Ρ‹Π΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ изящно Ρ€Π΅ΡˆΠ°ΡŽΡ‚ΡΡ ΡƒΠΌΠ½Ρ‹ΠΌΠΈ указатСлями. Π£ΠΌΠ½Ρ‹Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Π² C++ – это Π½Π΅ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ магичСскоС, встроСнноС Π² синтаксис языка, Π° Π½Π΅ Π±ΠΎΠ»Π΅Π΅ Ρ‡Π΅ΠΌ Π½Π°Π±ΠΎΡ€ классов ΠΈΠ· стандартной Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ. РазбСрёмся с Π½ΠΈΠΌΠΈ ΠΎΠ΄ΠΈΠ½ Π·Π° ΠΎΠ΄Π½ΠΈΠΌ.

std::unique_ptr

ΠŸΠ΅Ρ€Π²Ρ‹ΠΌ ΡƒΠΌΠ½Ρ‹ΠΌ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΌ, с ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ ΠΌΡ‹ познакомимся, Π±ΡƒΠ΄Π΅Ρ‚ std::unique_ptr [3]. Он ссылаСтся Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π² динамичСской памяти ΠΈ ΠΏΡ€ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄Π΅ ΠΈΠ· области видимости ΡƒΠ½ΠΈΡ‡Ρ‚ΠΎΠΆΠ°Π΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΠΌΡ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚. ВзглянСм Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΊΠΎΠ΄Π° Π½ΠΈΠΆΠ΅:

Листинг 5
        {
    std::unique_ptr<X> ptr(new X()); //ΠžΠ±ΡŠΠ΅ΠΊΡ‚ класса X создан Π² динамичСской памяти
} //Π—Π΄Π΅ΡΡŒ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ ptr ΠΏΠΎΠΊΠΈΠ΄Π°Π΅Ρ‚ свою ΠΎΠ±Π»Π°ΡΡ‚ΡŒ видимости ΠΈ уничтоТаСтся, Π½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄ этим удаляСт ΠΈΠ· памяти ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚
    

Когда std::unique_ptr Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΈΠ· области видимости, ΡƒΡ‚Π΅Ρ‡ΠΊΠΈ памяти Π½Π΅ происходит, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π² своСм дСструкторС ΡƒΠΌΠ½Ρ‹ΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ delete для ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ссылаСтся, высвобоТдая Ρ‚Π΅ΠΌ самым ΠΏΠ°ΠΌΡΡ‚ΡŒ.

Π’Π°ΠΆΠ½ΠΎ ΠΏΠΎΠ½ΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ Π²Π½ΡƒΡ‚Ρ€ΠΈ ΡƒΠΌΠ½Ρ‹Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ всё Ρ€Π°Π²Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ new/delete, ΠΎΠ½ΠΈ лишь ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ программисту Π½Π΅ Π΄Π΅Π»Π°Ρ‚ΡŒ этого ΠΈ, ΠΊΠ°ΠΊ слСдствиС, Π·Π°Ρ‰ΠΈΡ‰Π°ΡŽΡ‚ Π΅Π³ΠΎ ΠΎΡ‚ ошибок.

ΠžΡ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ с Π²Π½Π΅Π·Π°ΠΏΠ½Ρ‹ΠΌΠΈ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡΠΌΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΡ… ΡƒΠΌΠ½Ρ‹Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ (Π² частности std::unique_ptr) программистов Π·Π°Ρ‰ΠΈΡ‰Π°Π΅Ρ‚ Ρ€Π°Π·Π²Ρ‘Ρ€Ρ‚Ρ‹Π²Π°Π½ΠΈΠ΅ стСка (stack-unwinding [4]).

ΠŸΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎΠ΅ рассмотрСниС этого ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΠ° Π‘++ Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ Π·Π° Ρ€Π°ΠΌΠΊΠΈ ΡΡ‚Π°Ρ‚ΡŒΠΈ, Π½ΠΎ Π³Π»Π°Π²Π½ΠΎΠ΅, Ρ‡Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ Π·Π½Π°Ρ‚ΡŒ ΠΎ Π½Ρ‘ΠΌ – Ссли Π½Π° стСкС Π±Ρ‹Π» создан ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π° послС этого Π±Ρ‹Π»ΠΎ Π²Ρ‹Π±Ρ€ΠΎΡˆΠ΅Π½ΠΎ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅, C++ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎ Π²Ρ‹Π·ΠΎΠ²Π΅Ρ‚ дСструктор для этого ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°. Π­Ρ‚ΠΎ Π·Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ Ссли ΠΌΡ‹ ΠΎΠ±Π½ΠΎΠ²ΠΈΠΌ ΠΊΠΎΠ΄ Π² листингС 3 Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ использовал ΡƒΠΌΠ½Ρ‹Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ, Ρ‚ΠΎ избавимся ΠΎΡ‚ всСх Ρ‚Ρ€Ρ‘Ρ… Π²Ρ‹ΡˆΠ΅Π½Π°Π·Π²Π°Π½Π½Ρ‹Ρ… ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ:

Листинг 6
        std::unique_ptr<X> ptr(new X());
if (func()) {
    func2();
    return;
}
    

Π’Π΅ΠΏΠ΅Ρ€ΡŒ программисту Π½Π΅ Π½Π°Π΄ΠΎ ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ delete, Π° Π² случаС, Ссли ΠΎΠ΄Π½Π° ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ выбросит ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅, Ρ€Π°Π·Π²Ρ‘Ρ€Ρ‚Ρ‹Π²Π°Π½ΠΈΠ΅ стСка Π·Π°Ρ‰ΠΈΡ‚ΠΈΡ‚ нас ΠΎΡ‚ ΡƒΡ‚Π΅Ρ‡ΠΊΠΈ памяти.

И всё Π±Ρ‹ Ρ…ΠΎΡ€ΠΎΡˆΠΎ, Π½ΠΎ ΠΌΡ‹ ΠΏΠΎ-ΠΏΡ€Π΅ΠΆΠ½Π΅ΠΌΡƒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ new. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ new/delete соблюдалось, Π±Ρ‹Π»Π° ΠΏΡ€ΠΈΠ΄ΡƒΠΌΠ°Π½Π° функция std::make_unique [5], которая позволяСт ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ std::unique_ptr, Π½ΠΎ с нСсколькими Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ Ρ„ΠΈΡ‡Π°ΠΌΠΈ:

  • Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ new/delete ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ соблюдСно.
  • std::make_unique позволяСт Π½Π΅ ΠΏΠΈΡΠ°Ρ‚ΡŒ имя класса Π΄Π²Π°ΠΆΠ΄Ρ‹:
Листинг 7
        auto ptr = std::make_unique<X>();
    
  • std::make_unique Ρ€Π΅ΡˆΠ°Π΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠ³ΠΎ порядка вычислСния Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² (unspecified evaluation order). Рассмотрим ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ ΠΊΠΎΠ΄Π°:
Листинг 8
        void func(std::unique_ptr<A> a, std::unique_ptr<B> b) {}
int main() {
    func(std::unique_ptr<A>(new A()), std::unique_ptr<B>(new B()));
}
    

Π—Π΄Π΅ΡΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ΅Π½ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ порядок вычислСния Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²:

  1. new A()
  2. new B()
  3. std::unique_ptr<A>(...)
  4. std::unique_ptr<B>(...)

Если ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ new B() ΠΏΡ€ΠΎΠΈΠ·ΠΎΠΉΠ΄Π΅Ρ‚ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅, занятая ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ new A() ΠΏΠ°ΠΌΡΡ‚ΡŒ Π½Π΅ освободится, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΡƒΠΌΠ½Ρ‹ΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ для этого ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π΅Ρ‰Ρ‘ Π½Π΅ Π±Ρ‹Π» создан, Π° delete Π½ΠΈΠΊΡ‚ΠΎ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ ΠΈ Π½Π΅ собирался. ИспользованиС std::make_unique Ρ€Π΅ΡˆΠ°Π΅Ρ‚ ΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹Π΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹.

std::unique_ptr ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Ρ‚ΠΎΠ³Π΄Π°, ΠΊΠΎΠ³Π΄Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄Π½ΠΎΠ³ΠΎ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π°, ΠΎΠ΄Π½Π°ΠΊΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΏΡ€Π°Π²ΠΎ Π½Π° Π²Π»Π°Π΄Π΅Π½ΠΈΠ΅ ΠΊΠΎΠΌΡƒ-Ρ‚ΠΎ Π΄Ρ€ΡƒΠ³ΠΎΠΌΡƒ. Π§Ρ‚ΠΎΠ±Ρ‹ это ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ std::move[6]. Рассмотрим ΠΊΠΎΠ΄:

Листинг 9
        void func(std::unique_ptr<X> a) {}
int main() {
    auto a = std::make_unique<X>();
    func(a); //НС скомпилируСтся, std::unique_ptr нСльзя ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΈΠ½Π°Ρ‡Π΅ Ρƒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π±Ρ‹Π»ΠΎ Π±Ρ‹ нСсколько Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π΅Π²
    func(std::move(a)); //Π’Π»Π°Π΄Π΅Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ΠΎ Π² func, main большС Π½Π΅ Π²Π»Π°Π΄Π΅Π΅Ρ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ, Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄Π΅ ΠΈΠ· func ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΠ½ΠΈΡ‡Ρ‚ΠΎΠΆΠ΅Π½
}
    

Π Π°Π· std::unique_ptr нСльзя ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ, становится нСпонятно, ΠΊΠ°ΠΊ Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΡ‚ΡŒ ΠΊΠΎΠΌΡƒ-Ρ‚ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌΡ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π½Π΅ пСрСдавая Π΅ΠΌΡƒ ΠΏΡ€Π°Π²ΠΎ Π½Π° Π²Π»Π°Π΄Π΅Π½ΠΈΠ΅. ΠžΡ‡Π΅Π½ΡŒ просто: Π½ΡƒΠΆΠ½ΠΎ всСго лишь ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ простой ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° созданный ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° get(), ΠΊΠ°ΠΊ Π² листингС 10. Однако Π±ΡƒΠ΄ΡŒΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Ρ‚Π΅Π»ΡŒΠ½Ρ‹: Π½Π΅ допускайтС ситуации, ΠΊΠΎΠ³Π΄Π° std::unique_ptr вмСстС с Ρ…Ρ€Π°Π½ΠΈΠΌΡ‹ΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ Π±Ρ‹Π»ΠΈ ΡƒΠ½ΠΈΡ‡Ρ‚ΠΎΠΆΠ΅Π½Ρ‹, Π½ΠΎ Π³Π΄Π΅-Ρ‚ΠΎ ΠΏΠΎ-ΠΏΡ€Π΅ΠΆΠ½Π΅ΠΌΡƒ находится простой ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉ Π½Π° Π½Π΅Π²Π°Π»ΠΈΠ΄Π½ΡƒΡŽ (ΡƒΠΆΠ΅) ΠΎΠ±Π»Π°ΡΡ‚ΡŒ памяти.

Π”Π΅Π»Π°ΠΉΡ‚Π΅ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ простыС non owning ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ пСрСставали ΡΡƒΡ‰Π΅ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Π΄ΠΎ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ пСрСстанСт ΡΡƒΡ‰Π΅ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΎΠ½ΠΈ ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‚.
Листинг 10
        void func(X* a) {}
int main() {
    auto a = std::make_unique<X>();
    func(a.get());
}
    

Когда Π² ΠΊΠΎΠ΄Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ простыС ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ ΠΈ ΡƒΠΌΠ½Ρ‹Π΅, сразу становится понятно, Π³Π΄Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π²Π»Π°Π΄Π΅Π΅Ρ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ, Π° Π³Π΄Π΅ – Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚.

std::experimental::observer_ptr
На самом Π΄Π΅Π»Π΅ Π² ΠΊΠΎΠ΄Π΅ с ΡƒΠΌΠ½Ρ‹ΠΌΠΈ указатСлями Π½Π΅ всС простыС ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ – Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠ· Π½ΠΈΡ… ΠΌΠΎΠ³ΡƒΡ‚ ΠΈΠΌΠΈ Π²Π»Π°Π΄Π΅Ρ‚ΡŒ. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ ΠΎΡ‚Π΄Π΅Π»ΠΈΡ‚ΡŒ non owning, ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹Π΅ Ρ‡Π΅Ρ€Π΅Π· get() простыС ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ ΠΎΡ‚ Π»ΡŽΠ±Ρ‹Ρ… Π΄Ρ€ΡƒΠ³ΠΈΡ… простых ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΉ, Π±Ρ‹Π» ΠΏΡ€ΠΈΠ΄ΡƒΠΌΠ°Π½std::experimental::observer_ptr[7], Π½ΠΎ Π½Π° Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ ΠΎΠ½ Π΅Ρ‰Ρ‘ Π½Π΅ Π²ΠΎΡˆΡ‘Π» Π² стандарт.

std::unique_ptr – это ΡƒΠΌΠ½Ρ‹ΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ, ΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΠΎΠ΄ΡƒΠΌΠ°Ρ‚ΡŒ Π² ΠΏΠ΅Ρ€Π²ΡƒΡŽ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ, ΠΊΠΎΠ³Π΄Π° Ρ€Π΅ΡˆΠΈΡ‚Π΅ Ρ€Π°Π·ΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ Ρ‡Ρ‚ΠΎ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ Π² динамичСской памяти. Π­Ρ‚ΠΎ ваш ΡƒΠΌΠ½Ρ‹ΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ.

std::shared_ptr ΠΈ std::weak_ptr

std::unique_ptr ΠΈ ΠΏΡ€Π°Π²Π΄Π° Ρ…ΠΎΡ€ΠΎΡˆ, Π½ΠΎ ΠΎΠ½ Π½Π΅ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ Π² ситуации, ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ нСсколько ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Ρ€Π°Π±ΠΎΡ‚Π°Π»ΠΈ с ΠΎΠ΄Π½ΠΈΠΌ ΠΎΠ±Ρ‰ΠΈΠΌ рСсурсом ΠΈ Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚, ΠΊΠΎΠ³Π΄Π° всС эти ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ Π±Ρ‹Π»ΠΈ Π²Ρ‹Π³Ρ€ΡƒΠΆΠ΅Π½Ρ‹ ΠΈΠ· памяти, Π·Π° Π½Π΅Π½Π°Π΄ΠΎΠ±Π½ΠΎΡΡ‚ΡŒΡŽ автоматичСски выгрузился Π±Ρ‹ ΠΈ рСсурс.

Π’ Ρ‚Π°ΠΊΠΎΠΉ ситуации Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ std::shared_ptr [8]. Π­Ρ‚ΠΎΡ‚ ΡƒΠΌΠ½Ρ‹ΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρƒ ΠΈΠΌΠ΅Ρ‚ΡŒ нСсколько Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π΅Π², Π° ΠΊΠΎΠ³Π΄Π° всС Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Ρ‹ ΡƒΠ½ΠΈΡ‡Ρ‚ΠΎΠΆΠ°ΡŽΡ‚ΡΡ, уничтоТаСтся ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚. Π’Π°ΠΊΠΎΠ΅ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ достигаСтся Π·Π° счёт наличия ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ счётчика ссылок Π²Π½ΡƒΡ‚Ρ€ΠΈ std::shared_ptr. ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π·, ΠΊΠΎΠ³Π΄Π° Ρ‚Π°ΠΊΠΎΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ копируСтся, счётчик инкрСмСнтируСтся, Π° ΠΊΠΎΠ³Π΄Π° ΠΎΠ΄ΠΈΠ½ ΠΈΠ· ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΉ уничтоТаСтся – дСкрСмСнтируСтся. Π’ ΠΌΠΎΠΌΠ΅Π½Ρ‚, ΠΊΠΎΠ³Π΄Π° счётчик достигаСт нуля, ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ уничтоТаСтся. ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π½Π° ΠΊΠΎΠ΄:

Листинг 11
        {
    std::shared_ptr<X> ptr = std::make_shared<X>(); //Боздаётся ΠΎΠ±ΡŠΠ΅ΠΊΡ‚
    {
        std::shared_ptr<X> ptr2 = ptr; //Π’Π΅ΠΏΠ΅Ρ€ΡŒ Ρƒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π΄Π²Π° Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π°, Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½Π½Ρ‹Ρ… Π² Π²ΠΈΠ΄Π΅ ptr ΠΈ ptr2
    } //ptr2 Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΈΠ· области видимости, Π½ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π½Π΅ освобоТдаСтся, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ ptr, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠΎ-ΠΏΡ€Π΅ΠΆΠ½Π΅ΠΌΡƒ ссылаСтся Π½Π° Π½Π΅Π³ΠΎ
} //ptr Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΈΠ· области видимости, ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ уничтоТаСтся
    

std::make_shared являСтся Π°Π½Π°Π»ΠΎΠ³ΠΎΠΌ std::make_unique для std::shared_ptr.

Π‘ΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‚ ситуации, ΠΊΠΎΠ³Π΄Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ A Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΡΡ‹Π»Π°Ρ‚ΡŒΡΡ Π½Π° B, Π° B – Π½Π° A. Π­Ρ‚ΠΎ называСтся цикличСской ссылкой (cyclic reference/circular dependency). Π’ Ρ‚Π°ΠΊΠΎΠΌ случаС ΠΎΠ±Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π³Ρ€ΡƒΠΆΠ΅Π½Ρ‹ ΠΈΠ· памяти.

Π§Ρ‚ΠΎΠ±Ρ‹ Ρ€Π°Π·ΠΎΡ€Π²Π°Ρ‚ΡŒ Ρ†ΠΈΠΊΠ»ΠΈΡ‡Π½ΠΎΡΡ‚ΡŒ, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ std::weak_ptr[9]. Π­Ρ‚ΠΎ фактичСски ΡƒΠΌΠ½Ρ‹ΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ non owning, ΠΏΡ€Π΅Π΄Π½Π°Π·Π½Π°Ρ‡Π΅Π½Π½Ρ‹ΠΉ для использования ΠΈΠΌΠ΅Π½Π½ΠΎ с std::shared_ptr. ΠšΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ std::weak_ptr Π½Π΅ ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ счётчик Π² std::shared_ptr, Π° Π·Π½Π°Ρ‡ΠΈΡ‚ ΠΈ Π½Π΅ Π·Π°Ρ‰ΠΈΡ‰Π°Π΅Ρ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΎΡ‚ уничтоТСния. ΠŸΡ€ΠΈ этом всСгда имССтся Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, сущСствуСт Π»ΠΈ Π΅Ρ‰Ρ‘ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ссылаСтся std::weak_ptr, ΠΈΠ»ΠΈ Π½Π΅Ρ‚. Π’Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° ΠΊΠΎΠ΄:

Листинг 12
        class Owner {
public:
    std::shared_ptr<X> owningPtr;

    Owner() {
        owningPtr = std::make_shared<X>();
    }
};

class User {
    std::weak_ptr<X> usingPtr;
public:
    User(std::weak_ptr<X> object) {
        usingPtr = object;
    }

    void use() {
        if (std::shared_ptr<X> object = usingPtr.lock()) { //ΠŸΠΎΠΏΡ‹Ρ‚ΠΊΠ° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ std::shared_ptr ΠΈΠ· std::weak_ptr, Ссли Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Ρ‘Π½ пустой std::shared_ptr, Π·Π½Π°Ρ‡ΠΈΡ‚, ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΡƒΠΆΠ΅ Π±Ρ‹Π» ΡƒΠ΄Π°Π»Ρ‘Π½
	    object->func();
        } else {
            //ΠžΠ±ΡŠΠ΅ΠΊΡ‚ ΡƒΠΆΠ΅ ΡƒΠ΄Π°Π»Ρ‘Π½
        }
    }
};

int main() {
    Owner owner;
    User user(owner.owningPtr);
    user.use();
}
    

Π’ΠΎΠΎΠ±Ρ‰Π΅ говоря, std::weak_ptr Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ всСгда, ΠΊΠΎΠ³Π΄Π° Π½Π°Π΄ΠΎ ΡΡΡ‹Π»Π°Ρ‚ΡŒΡΡ Π½Π° управляСмый std::shared_ptr ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π½ΠΎ Π½Π΅ Π·Π°Ρ‰ΠΈΡ‰Π°Ρ‚ΡŒ Π΅Π³ΠΎ ΠΎΡ‚ уничтоТСния.

std::auto_ptr
БущСствуСт ΠΎΠ΄Π½ΠΎ самоС Π³Π»Π°Π²Π½ΠΎΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ использования std::auto_ptr[10]: Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ std::auto_ptr. Π­Ρ‚ΠΎΡ‚ ΡƒΠΌΠ½Ρ‹ΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π±Ρ‹Π» ΠΏΠΎΠΌΠ΅Ρ‡Π΅Π½ ΠΊΠ°ΠΊ ΡƒΡΡ‚Π°Ρ€Π΅Π²ΡˆΠΈΠΉ Π² C++ 11, Π° Π² C++ 17 Π±Ρ‹Π» ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ ΡƒΠ΄Π°Π»Ρ‘Π½ ΠΈΠ· стандарта языка.

Π’Ρ‹Π²ΠΎΠ΄Ρ‹

ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ программист Π½Π° C++ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡƒΠΌΠ΅Ρ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡƒΠΌΠ½Ρ‹Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ. Π£ΠΌΠ½Ρ‹Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΠΈ – это ваш способ управлСния динамичСской ΠΏΠ°ΠΌΡΡ‚ΡŒΡŽ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ. std::unique_ptr – это ваш ΡƒΠΌΠ½Ρ‹ΠΉ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ. ИспользованиС ΡƒΠΌΠ½Ρ‹Ρ… ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΉ Π½Π΅ ΠΏΡ€ΠΎΡ‚ΠΈΠ²ΠΎΡ€Π΅Ρ‡ΠΈΡ‚ использованию простых ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΉ, Π² случаС, Ссли послСдниС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹, Π° Π½Π΅ Π²Π»Π°Π΄Π΅ΡŽΡ‚ ΠΈΠΌΠΈ. std::auto_ptr – Π·Π»ΠΎ.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ

ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ

 
 

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•

Подпишись

Π½Π° push-увСдомлСния