In the case of using a std::unique_ptr to automatically deallocate memory upon exiting a scoped block, why not just use the stack?

你。 提交于 2020-03-04 18:44:25

问题


This is a great answer about smart pointers, such as unique pointers: What is a smart pointer and when should I use one?.

Here is an example they provide as the simplest use of a unique pointer:

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.
}

However, this begs the question: in cases such as this, where the goal is to simply delete the object (free the memory) the unique pointer points to when it goes out of scope, why not just put the whole object on the stack instead, like this??

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.
}

It seems to me the only logic can be that some objects are so stinking large they may overflow the stack, as stacks seem to be limited to a few dozen KB to a few MB (C/C++ maximum stack size of program), whereas a heap can be hundreds of GB!

What's the logic? Give me some insight here into this seemingly unnecessary use case of the unique pointer. What am I missing?

Related:

  1. "Another feature of the stack to keep in mind, is that there is a limit (varies with OS) on the size of variables that can be stored on the stack. This is not the case for variables allocated on the heap." (https://gribblelab.org/CBootCamp/7_Memory_Stack_vs_Heap.html)

回答1:


While this is not a terrible useful example per-se, it becomes with some slight variations.

  1. Polymorphism
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();
}
  1. Non-standard deleter
{ 
    auto close = [] (FILE* fp) { fclose(fp);};
    std::unique_ptr<FILE, decltype(close)> ptr(fopen("name"), close);
} // closes file
  1. Dynamic Array (you can arguably use a vector)
{ 
    std:: unique_ptr<int[]> ptr( new int [n]);
}
  1. Conditional creation of an object. (Only in C++11 and 14, after that use std::optional)
void blah (bool smth)
{
    std::unique_ptr<T> opt;
    if (smth) {
        opt = std::unique_ptr<T>(new T);
    }
}



回答2:


Size is not the primary concern, although it may be important if you have recursion, for example (I saw a library allocating 64 KiB buffer on stack, in a recursive function. But Musl provides 128 KiB stacks [to make threads lightweight], so...) But the object may be polymorphic, and not even created “right there” but rather returned from some function (as a pointer); unique_ptr may be handy to store that.

Besides that, unique_ptr (unlike auto_ptr AFAIK) is not restricted to on-stack usage. It can be a class member as well. Also it is not required to actually store anything, you may assign and reset it at any time.

Moreover, it is not restricted to C++ classes, you can store anything requiring cleanup there, like file descriptor or FILE*, for example.



来源:https://stackoverflow.com/questions/60421416/in-the-case-of-using-a-stdunique-ptr-to-automatically-deallocate-memory-upon-e

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!