Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Stack/Heap/smart pointers question.



  • Hello,
    For quite some time something is bugging me and would appreciate if someone would explain what I am not understanding.

    From my knowledge, whenever I use an object inside a function I should use stack-based allocation and when I need to have an object available across functions/objects/etc. I should use heap-based allocation, right?
    As far as I also know, smart pointers destroy objects when they go out of scope, right?

    So what's the point of using a smart pointers instead of stack-based allocation? Aren't smart pointers just doing the same thing with extra steps?


  • Moderators

    @adutzu89 said in Stack/Heap/smart pointers question.:

    As far as I also know, smart pointers destroy objects when they go out of scope, right?

    So what's the point of using a smart pointers instead of stack-based allocation? Aren't smart pointers just doing the same thing with extra steps?

    Not quite.

    There are different types of smart pointers which serve different purposes: https://stackoverflow.com/questions/106508/what-is-a-smart-pointer-and-when-should-i-use-one

    In summary, C++ has 3 standard smart pointers (not counting std::auto_ptr which has been deprecated and removed from C++17):

    • std::unique_ptr
    • std::shared_ptr
    • std::weak_ptr

  • Lifetime Qt Champion

    @adutzu89 said in Stack/Heap/smart pointers question.:

    So what's the point of using a smart pointers instead of stack-based allocation?

    The point is that you can't allocate everything on the stack.
    So, often you have to use heap and then smart pointers should be used to make sure memory is freed again.
    Every "new" requires "delete" at some point and that's exactly what smart pointers are used for.



  • @JKSH , @jsulm , thank you for your inputs.
    Based on your comments, I read more on heap, stack and smart pointers and came to the conclusion that I need to learn more.
    My misunderstanding came from the lack of knowledge of stack's maximum size.

    Anyway from the quick reading I made on the internet I understand that you can use smart pointers as class members for heap objects, is that correct?


  • Moderators

    @adutzu89 said in Stack/Heap/smart pointers question.:

    Anyway from the quick reading I made on the internet I understand that you can use smart pointers as class members for heap objects, is that correct?

    Yes, smart pointers can be used as class members.

    They can also be placed inside other containers.

    class MyClass {
    public:
        MyClass();
    
    private:
        std::shared_ptr<OtherClass> m_data;
        std::vector< std::shared_ptr<YetAnotherClass> > m_list;
    }
    


  • @JKSH said in Stack/Heap/smart pointers question.:

    And you can also put smart pointers in containers.
    class MyClass {
    public:
    MyClass();

    private:
    std::shared_ptr<OtherClass> m_data;
    std::vector< std::shared_ptr<YetAnotherClass> > m_list;
    }

    I see, thank you.


  • Moderators

    @adutzu89 said in Stack/Heap/smart pointers question.:

    So what's the point of using a smart pointers instead of stack-based allocation?

    Here it goes my usual missive ...

    Smart pointers are not pointers at all. They are a stack-based (or rather auto-storage based) objects which manage a block of memory in the heap. C++ is a stack-based language, everything you work with is rooted in the stack, even a raw pointer resides in the stack (while it may point to a data block in the heap). The stack is important and useful (and hardware implemented) because:

    • It's contiguous (which the heap isn't)
    • It's automatically freed whenever scope goes out (which the heap isn't). E.g. when a function exits, the stack is automatically unwound.

    However it has one major limitation - the size of an object which is to be allocated on the stack must be known at compile time, there is no workaround for this, it's an architectural "issue". That specific drawback is rectified by the heap - where one can allocate based on runtime-known size of the memory block.



  • @kshegunov said in Stack/Heap/smart pointers question.:

    the size of an object which is to be allocated on the stack must be known at compile time, there is no workaround for this, it's an architectural "issue".

    Now, you know I always read what you write with interest, my friend! But I don't understand why you pick this out as a "stricture" of stack allocation? What about alloca(), which has been there since year dot in Unix, and I see is still supported by gcc and in msvc (_alloca())? I'm not suggesting people go out and start using it, but it does not require a compile-time constant argument, so how does this relate to your "architectural" claim above?


  • Moderators

    @JonB said in Stack/Heap/smart pointers question.:

    the size of an object which is to be allocated on the stack must be known at compile time, there is no workaround for this, it's an architectural "issue".

    Now, you know I always read what you write with interest, my friend! But I don't understand why you pick this out as a "stricture" of stack allocation?

    For the purpose of pedagogy. There's a gnu extension which allows you a stack based array with a runtime constant as size, as well, but it's not standard.

    What about alloca(), which has been there since year dot in Unix, and I see is still supported by gcc and in msvc (_alloca())?

    Did not mention it, and specifically avoided it, because the memory isn't freed when you leave the current scope, it's freed when the stack frame's popped. This is rather dangerous and can be messy. And in the C++ world *alloc() functions are discouraged in most cases. If you want an array of objects and you take the memory block through alloca you need to do a placement new on top of it to follow C++ semantics, so your constructors are called, and finally you need to manually invoke the destructors before exiting. This isn't ideal in the world of RAII.

    I'm not suggesting people go out and start using it, but it does not require a compile-time constant argument, so how does this relate to your "architectural" claim above?

    Not too well. I was specifically thinking of push and pop. Granted, alloca will move the top of the stack frame, and as with any integer that can be done at runtime, but it's a bad idea generally. In fact this is what the compiler does when you do a regular stack allocation - it moves the stack pointer the size of the object off the stack frame pointer (i.e. move the esp register in relation to the ebp register), with the exception that it validates the consistency at compile time (and static code analysis can be easily supported). Also the meaning is clearer, as you know the memory is local. With alloca you can pass the pointer to somewhere else, and without realizing that pointer's data block can get invalidated the moment you leave the current stack frame. It's not for the faint of heart.


Log in to reply