Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to allocate memory properly in C++?
QtWS25 Last Chance

How to allocate memory properly in C++?

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 6 Posters 3.0k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Maya O
    wrote on 31 Mar 2020, 08:27 last edited by Maya O
    #1

    In C/C++ there are three ways to allocate memory for objects:

    • Dynamic allocation in stack
    • Dynamic allocation in heap
    • Static allocation in bss/data

    Each of these areas has some benefits and some drawbacks, like allocation in stack is faster than heap but it is limited.

    Now my question is when should I use which area in what condition to instantiate objects?
    As objects of QApplication and QMainWindow are the main objects of application and their existance is a must for lifetime of programme, isn't it better to instantiate them inside bss/data to decrease stack memory usage and prevent stack overflow?

    1 Reply Last reply
    1
    • M Offline
      M Offline
      mrjj
      Lifetime Qt Champion
      wrote on 31 Mar 2020, 08:42 last edited by
      #2

      Hi

      One has to take into account the Qt ownership system
      https://doc.qt.io/qt-5/objecttrees.html

      so while this is perfectly legal

      class MainWindow : QMainWindow {
      QPushbutton Button;
      }

      you might run into issues if you the button put in a layout as then both Qt and the normal c++ will try to delete it.

      For other non-visual classes, it makes perfect sense to have them as non pointer members.

      for static allocation (using static keyword) then be aware that no QObject may exist before the QApplication created in main.

      So for anything that makes up a hierarchy , you will often use heap.
      For local use / you will often use stack.
      Like

      Dialog myDialog;
      myDialog.exec();

      no reason to put myDialog on the heap as exec is blocking so it wont run out of scope.

      So the right way depends on the use case and if visual.

      1 Reply Last reply
      6
      • C Offline
        C Offline
        Chris Kawa
        Lifetime Qt Champion
        wrote on 31 Mar 2020, 14:48 last edited by Chris Kawa
        #3

        Now my question is when should I use which area in what condition to instantiate objects?

        If you expect an algorithm like if(something) use stack else if (something else) use heap else use static storage then there's no such nard rules. The answer is "it depends" and the amount of factors it depends on is enough to write several books on the topic (and there indeed are). I know this might not sound like satisfactory answer if you're new to this but to help you there are some rough guidelines. Keep in mind though that it's all they are and there are plenty of exceptions and reasons not to follow them.

        Anyway, for QObjects it's pretty much what @mrjj said:

        • Qt manages parent/child objects lifetime, so anything that is meant to be deleted by the parent needs to go on the heap
        • Anything else (which is not much - root objects, locals, scope bound stuff) goes on the stack.
        • Never create static QObjects. The order of initialization/destruction for those is unspecified and that doesn't work with Qt. Some classes might work, others might seem to work but don't, many will straight up crash your app.

        As for non Qt, static storage is for data and uninitialized stuff. While there's a lot you can use it for don't put every little thing you can in there because they are bad for cache locality, have ordering issues, especially when mixing with dynamic libraries and such. Stuffing a lot in there also increases your executable image size, which can be an issue too in some environments. Keep it simple - use it for constants, arrays of data, string literals etc.
        Stack is your bread and butter. It's the memory part managed entirely by your app, so it's the fastest. Use it as much as you can. The reasons you can't include - the thing is too big (stack is small), its lifetime doesn't match any reasonable scope or the API you use requires you not to.
        Heap is the warehouse. It's big but it takes time to allocate and free space in it. Use it to store a lot of stuff or when you can't use stack. Using heap is slower because allocation/deallocation goes through the OS, and, since it's a lot of space, it has worse cache locality than stack.

        1 Reply Last reply
        3
        • M Offline
          M Offline
          Maya O
          wrote on 31 Mar 2020, 17:02 last edited by
          #4

          How can I moderate stack to prevent stack overflow?
          How can I evaluate my programme to measure maximum stack usage during runtime?

          C 1 Reply Last reply 31 Mar 2020, 17:46
          0
          • M Maya O
            31 Mar 2020, 17:02

            How can I moderate stack to prevent stack overflow?
            How can I evaluate my programme to measure maximum stack usage during runtime?

            C Offline
            C Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on 31 Mar 2020, 17:46 last edited by
            #5

            How can I moderate stack to prevent stack overflow?

            At runtime? the easiest way is just don't put stuff there. If you're worrying about overflowing the stack with normal usage you probably already put too much there. Most objects have sizes counted in bytes, sometimes dozens or hundreds. For example if you have a 30 function deep call stack and each function has, say 10 variables, being, for example, 8 bytes in size, you're looking at a stack usage below 3KB. There's plenty of room on the stack for usual tasks and it's not that easy to overflow. Just don't go crazy and put large arrays there.
            I mean you could put some variables on the stack, take their addresses and do some arithmetic to calculate how much memory from the stack you're consuming. Your particular OS API might also have some functions to tell you the stack base address etc. Most compilers also let you override the default stack size via some switches, but again, that's something you would rarely do, and from what I've seen it's usually to reduce the default stack size in a massive multithreaded apps to reduce overall app memory footprint.

            Are you asking because you do heave a stack overflow problem or just in case? Because it's not something you worry too much about in day to day programming.

            How can I evaluate my programme to measure maximum stack usage during runtime?

            There are some profiling tools and APIs for that. Linux has getrusage() which I think could tell you something. There are tools like Intel VTune which profiles all sorts of memory usage aspects, but again, that's not something you usually do, only in cases where you have an actual stack overflow problems.

            M 1 Reply Last reply 1 Apr 2020, 17:03
            4
            • S Offline
              S Offline
              SimonSchroeder
              wrote on 1 Apr 2020, 07:13 last edited by SimonSchroeder 4 Feb 2020, 06:45
              #6

              As a general rule of thumb I would say prefer to put your variables on the stack. Reason number one for this is object lifetime: it is managed automatically when putting something on the stack. Sure, now we have smart pointers which also help manage lifetimes. But a local variable has restricted lifetime within the local scope (which a shared_ptr might not) which makes reasoning about it quite easy. The second reason is speed. As already mentioned allocation/deallocation on the heap is comparatively slow. Especially for short object lifetime with little work in between it is not worth the hassle (in 99% of the time you wouldn't allocate an int or a double on the heap).

              Large objects, however, should live on the heap. Most of the time this is only the case with arrays of data. These usually have a number of entries not known at compile time. There is no way (yet) in C++ to dynamically allocate arrays on the heap stack. There is, however, this functionality in C. Still, there are few case where you should do that, as you correctly noted that the stack is limited in size. Speaking of C++, most of the time you should use a vector class (like std::vector) instead of plain arrays. The vector object can live on the stack (managing lifetime correctly) whereas internally its array is allocated on the heap. Together with move semantics and guaranteed return value optimization (since C++17???) you can even return a std::vector "allocated" on the stack (it's quite cheap independent of the number of elements it stores).

              BTW, usually arrays and vectors tend to be a little larger. If you just do a tiny amount of work on every element of the array/vector the cost for allocation/deallocation of the array on the heap quickly amortizes.

              Extended object lifetime (continuing after leaving a function) is also a reason heap storage. For non-moveable objects it is advisable if a copy is expensive, for non-copyable objects it is even the only possible way (if they are also non-moveable).

              As Chris Kawa already mentioned don't try to forceably use static storage. I will not go into detail here as it really shouldn't be your common case.

              Still, there is more to the discussion. When talking about object oriented programming you will soon encounter runtime polymorphism. This is the case with virtual methods inside classes. For simple case you could still allocate them on the stack and pass a reference or pointer to the base class to other functions. As soon as you want to store objects of an inheritance hierarchy in an array or vector the common approach is to use pointers (or even smart pointers). You simply cannot store the object directly inside a polymorphic container. That last sentence is only partially true as with std::variant there is a way to store objects directly inside the container. If it actually makes sense depends on the object sizes (if they differ largely) and the type of operations you do on the container (erasing something in the middle of a std::vector or sorting is expensive on objects because of copying – pointers to objects are a lot cheaper in these cases).

              As Chris Kawa already mentioned classes derived from QObject usually manage object lifetime differently. As long as an object has a parent its parent will call delete on the object when the parent is destroyed. This implies allocation on the heap. There is no trick around that. QObjects with a null-pointer parent can, in general, be put on the stack. With Qt Widgets you should note that putting a widget into a layout reparents the object.

              I work on large code bases where speed is paramount. So, I follow my own advice and allocate as much as possible on the stack. I can only confirm what Chris Kawa says that the stack size has never been a problem. I have run out of stack in a few cases. Number one reason is bugs. Ocassionally, by accident I have introduced infinite recursions. This can easily happen when connecting signals of widgets to slots that manipulate widgets themselves. A stack overflow usually occurs shortly after passing a stack depth of a 1000 function calls. Sometimes, a recursive function looks like the best tool (e.g. traversing a tree). So, you should know that there is a limit. Recursion can always be rewritten by using a loop. This is your way out if you run into trouble. Some compilers, e.g. GCC, can recognize tail recursion and optimize it to be similar to a loop (avoiding allocation of deep stacks). The only second reason for a stack overflow I ever encountered was found in using Fortran. There it is quite easy to allocate arrays on the stack. When reaching several million entries these large arrays are a problem. It will not be a problem if you follow the advice from above to allocate arrays on the heap or use vector classes directly.

              aha_1980A 1 Reply Last reply 1 Apr 2020, 08:05
              3
              • S SimonSchroeder
                1 Apr 2020, 07:13

                As a general rule of thumb I would say prefer to put your variables on the stack. Reason number one for this is object lifetime: it is managed automatically when putting something on the stack. Sure, now we have smart pointers which also help manage lifetimes. But a local variable has restricted lifetime within the local scope (which a shared_ptr might not) which makes reasoning about it quite easy. The second reason is speed. As already mentioned allocation/deallocation on the heap is comparatively slow. Especially for short object lifetime with little work in between it is not worth the hassle (in 99% of the time you wouldn't allocate an int or a double on the heap).

                Large objects, however, should live on the heap. Most of the time this is only the case with arrays of data. These usually have a number of entries not known at compile time. There is no way (yet) in C++ to dynamically allocate arrays on the heap stack. There is, however, this functionality in C. Still, there are few case where you should do that, as you correctly noted that the stack is limited in size. Speaking of C++, most of the time you should use a vector class (like std::vector) instead of plain arrays. The vector object can live on the stack (managing lifetime correctly) whereas internally its array is allocated on the heap. Together with move semantics and guaranteed return value optimization (since C++17???) you can even return a std::vector "allocated" on the stack (it's quite cheap independent of the number of elements it stores).

                BTW, usually arrays and vectors tend to be a little larger. If you just do a tiny amount of work on every element of the array/vector the cost for allocation/deallocation of the array on the heap quickly amortizes.

                Extended object lifetime (continuing after leaving a function) is also a reason heap storage. For non-moveable objects it is advisable if a copy is expensive, for non-copyable objects it is even the only possible way (if they are also non-moveable).

                As Chris Kawa already mentioned don't try to forceably use static storage. I will not go into detail here as it really shouldn't be your common case.

                Still, there is more to the discussion. When talking about object oriented programming you will soon encounter runtime polymorphism. This is the case with virtual methods inside classes. For simple case you could still allocate them on the stack and pass a reference or pointer to the base class to other functions. As soon as you want to store objects of an inheritance hierarchy in an array or vector the common approach is to use pointers (or even smart pointers). You simply cannot store the object directly inside a polymorphic container. That last sentence is only partially true as with std::variant there is a way to store objects directly inside the container. If it actually makes sense depends on the object sizes (if they differ largely) and the type of operations you do on the container (erasing something in the middle of a std::vector or sorting is expensive on objects because of copying – pointers to objects are a lot cheaper in these cases).

                As Chris Kawa already mentioned classes derived from QObject usually manage object lifetime differently. As long as an object has a parent its parent will call delete on the object when the parent is destroyed. This implies allocation on the heap. There is no trick around that. QObjects with a null-pointer parent can, in general, be put on the stack. With Qt Widgets you should note that putting a widget into a layout reparents the object.

                I work on large code bases where speed is paramount. So, I follow my own advice and allocate as much as possible on the stack. I can only confirm what Chris Kawa says that the stack size has never been a problem. I have run out of stack in a few cases. Number one reason is bugs. Ocassionally, by accident I have introduced infinite recursions. This can easily happen when connecting signals of widgets to slots that manipulate widgets themselves. A stack overflow usually occurs shortly after passing a stack depth of a 1000 function calls. Sometimes, a recursive function looks like the best tool (e.g. traversing a tree). So, you should know that there is a limit. Recursion can always be rewritten by using a loop. This is your way out if you run into trouble. Some compilers, e.g. GCC, can recognize tail recursion and optimize it to be similar to a loop (avoiding allocation of deep stacks). The only second reason for a stack overflow I ever encountered was found in using Fortran. There it is quite easy to allocate arrays on the stack. When reaching several million entries these large arrays are a problem. It will not be a problem if you follow the advice from above to allocate arrays on the heap or use vector classes directly.

                aha_1980A Offline
                aha_1980A Offline
                aha_1980
                Lifetime Qt Champion
                wrote on 1 Apr 2020, 08:05 last edited by
                #7

                @SimonSchroeder said in How to allocate memory properly in C++?:

                There is no way (yet) in C++ to dynamically allocate arrays on the heap

                I think you meant to write:

                There is no way (yet) in C++ to dynamically allocate arrays on the stack.

                Regards

                Qt has to stay free or it will die.

                JonBJ 1 Reply Last reply 1 Apr 2020, 08:31
                2
                • aha_1980A aha_1980
                  1 Apr 2020, 08:05

                  @SimonSchroeder said in How to allocate memory properly in C++?:

                  There is no way (yet) in C++ to dynamically allocate arrays on the heap

                  I think you meant to write:

                  There is no way (yet) in C++ to dynamically allocate arrays on the stack.

                  Regards

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on 1 Apr 2020, 08:31 last edited by
                  #8

                  @aha_1980
                  Use alloca() ;-) [Not seriously recommended, and not a part of the C++ spec.]

                  1 Reply Last reply
                  1
                  • C Chris Kawa
                    31 Mar 2020, 17:46

                    How can I moderate stack to prevent stack overflow?

                    At runtime? the easiest way is just don't put stuff there. If you're worrying about overflowing the stack with normal usage you probably already put too much there. Most objects have sizes counted in bytes, sometimes dozens or hundreds. For example if you have a 30 function deep call stack and each function has, say 10 variables, being, for example, 8 bytes in size, you're looking at a stack usage below 3KB. There's plenty of room on the stack for usual tasks and it's not that easy to overflow. Just don't go crazy and put large arrays there.
                    I mean you could put some variables on the stack, take their addresses and do some arithmetic to calculate how much memory from the stack you're consuming. Your particular OS API might also have some functions to tell you the stack base address etc. Most compilers also let you override the default stack size via some switches, but again, that's something you would rarely do, and from what I've seen it's usually to reduce the default stack size in a massive multithreaded apps to reduce overall app memory footprint.

                    Are you asking because you do heave a stack overflow problem or just in case? Because it's not something you worry too much about in day to day programming.

                    How can I evaluate my programme to measure maximum stack usage during runtime?

                    There are some profiling tools and APIs for that. Linux has getrusage() which I think could tell you something. There are tools like Intel VTune which profiles all sorts of memory usage aspects, but again, that's not something you usually do, only in cases where you have an actual stack overflow problems.

                    M Offline
                    M Offline
                    Maya O
                    wrote on 1 Apr 2020, 17:03 last edited by
                    #9

                    @Chris-Kawa said in How to allocate memory properly in C++?:

                    Are you asking because you do heave a stack overflow problem or just in case?

                    No. I care about the quality of my code and optimization of generated binary a lot. So I wanted to know more about handling memory management in C++/Qt

                    1 Reply Last reply
                    0
                    • M Offline
                      M Offline
                      mrjj
                      Lifetime Qt Champion
                      wrote on 1 Apr 2020, 20:21 last edited by
                      #10

                      Hi
                      Just a note about " dynamically allocate arrays on the stack."

                      "draft C++14 now allows stack-based arrays to have a size determined at run time:"

                      void f(std::size_t n)
                      {
                      int a[n];
                      ...
                      }

                      https://isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meeting

                      So that didnt make to the release ?

                      Or do we generally mean more dynamic?

                      JonBJ 1 Reply Last reply 1 Apr 2020, 20:26
                      0
                      • M mrjj
                        1 Apr 2020, 20:21

                        Hi
                        Just a note about " dynamically allocate arrays on the stack."

                        "draft C++14 now allows stack-based arrays to have a size determined at run time:"

                        void f(std::size_t n)
                        {
                        int a[n];
                        ...
                        }

                        https://isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meeting

                        So that didnt make to the release ?

                        Or do we generally mean more dynamic?

                        JonBJ Offline
                        JonBJ Offline
                        JonB
                        wrote on 1 Apr 2020, 20:26 last edited by JonB 4 Jan 2020, 20:27
                        #11

                        @mrjj
                        E.g. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0785r0.html [from 2017]

                        Both facilities were removed from C++14 and instead put into a separate Technical Specification in Chicago, September 2013

                        ? :)

                        M 1 Reply Last reply 1 Apr 2020, 20:29
                        2
                        • JonBJ JonB
                          1 Apr 2020, 20:26

                          @mrjj
                          E.g. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0785r0.html [from 2017]

                          Both facilities were removed from C++14 and instead put into a separate Technical Specification in Chicago, September 2013

                          ? :)

                          M Offline
                          M Offline
                          mrjj
                          Lifetime Qt Champion
                          wrote on 1 Apr 2020, 20:29 last edited by
                          #12

                          @JonB
                          Ok so we didnt get that. thx :)

                          1 Reply Last reply
                          0

                          1/12

                          31 Mar 2020, 08:27

                          • Login

                          • Login or register to search.
                          1 out of 12
                          • First post
                            1/12
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved