В случае использования std :: unique_ptr для автоматического освобождения памяти при выходе из блока с областью видимости, почему бы просто не использовать стек? - PullRequest
0 голосов
/ 26 февраля 2020

Это отличный ответ об умных указателях, таких как уникальные указатели: Что такое умный указатель и когда мне следует его использовать? .

Вот пример, который они предоставляют в качестве простейшее использование уникального указателя:

void f()
{
    {
       std::unique_ptr<MyObject> ptr(new MyObject(my_constructor_param));
       ptr->DoSomethingUseful();
    } // ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

Однако возникает вопрос: в таких случаях, как этот, цель состоит в том, чтобы просто удалить объект (освободить память), на который указывает уникальный указатель, когда он выходит из области видимости, почему бы просто не поместить весь объект в стек вместо этого, как этот ??

void f()
{
    {
       MyObject myobj(my_constructor_param);
       myobj.DoSomethingUseful();
    } // myobj goes out of scope -- 
      // and is automatically destroyed.

    // myobj.Oops(); // Compile error: "myobj" not defined
                     // since it is no longer in scope.
}

Мне кажется, что only logi c может быть, что некоторые объекты настолько вонючие, что могут переполнять стек, так как стеки, кажется, ограничены несколькими десятками КБ до нескольких МБ ( C / C ++ максимальный размер стека программы ), тогда как куча может составлять сотни ГБ!

Что за логика c? Дайте мне некоторое представление об этом, казалось бы, ненужном варианте использования уникального указателя. Чего мне не хватает?

Связанный:

  1. "Еще одна особенность стека, которую следует иметь в виду, заключается в том, что существует ограничение (зависит от ОС) на размер переменных, которые может храниться в стеке. Это не относится к переменным, расположенным в куче. " (https://gribblelab.org/CBootCamp/7_Memory_Stack_vs_Heap.html)

Ответы [ 2 ]

4 голосов
/ 26 февраля 2020

Хотя это не очень полезный пример сам по себе, он становится с некоторыми небольшими изменениями.

  1. Полиморфизм
struct Base { void blah() { std::cout << "Base\n";}};
struct Derived : Base { void blah() {std::cout << "Derived\n";}};

void blub(bool which) { 
    std::unique_ptr<Base> ptr = which ? new Base : new Derived;
    ptr->blah();
}
Нестандартный удалитель
{ 
    auto close = [] (FILE* fp) { fclose(fp);};
    std::unique_ptr<FILE, decltype(close)> ptr(fopen("name"), close);
} // closes file
Dynami c Массив (можно использовать вектор)
{ 
    std:: unique_ptr<int[]> ptr( new int [n]);
}
Условное создание объекта. (Только в C ++ 11 и 14, после этого используйте std::optional)
void blah (bool smth)
{
    std::unique_ptr<T> opt;
    if (smth) {
        opt = std::unique_ptr<T>(new T);
    }
}
0 голосов
/ 26 февраля 2020

Размер не имеет первостепенного значения, хотя он может быть важен, если у вас есть, например, рекурсия (я видел библиотеку, выделяющую буфер 64 КиБ для стека, в рекурсивной функции. Но Musl предоставляет стеки 128 КиБ [для облегчения потоков ], так ...) Но объект может быть полиморфным c, и даже не создан "прямо там", а скорее возвращен из какой-то функции (как указатель); unique_ptr может быть удобно хранить это.

Кроме того, unique_ptr (в отличие от auto_ptr AFAIK) не ограничивается использованием в стеке. Это может быть и ученик. Также на самом деле ничего не требуется хранить, вы можете назначить и сбросить его в любое время.

Более того, это не ограничивается классами C ++, вы можете хранить там все, что требует очистки, например дескриптор файла или FILE * Например.

...