Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. Class properties in stack or heap?
QtWS25 Last Chance

Class properties in stack or heap?

Scheduled Pinned Locked Moved Solved C++ Gurus
stackmemory
15 Posts 5 Posters 4.6k 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.
  • E Offline
    E Offline
    Exotic_Devel
    wrote on 7 Nov 2019, 20:17 last edited by Exotic_Devel 11 Jul 2019, 20:20
    #1

    There is much controversy as to where to allocate a particular object. Some say forever to give preference to the stack because allocating and releasing heap objects comes at a cost and is harder to administer. On the other hand there are those who say that the best thing is to allocate in the heap because the stack is somewhat limited.
    This really confuses me because I don't know which side is right.
    Recommendations say that in the heap should be large objects, but what is the definition of large? How much would be considerable large and how to measure it?
    Finally, applying these ideas to the properties of a class, where should its properties be allocated? In the stack?

    class Person
    {
    	private:
    		QString name;
    		QList<QString> aliases;
    		QDate birthday;
    		int children_number;
    
    	public:
    		Person(QString &name, QList<QString> &aliases, QDate &birthday, int &children_number);
    };
    

    Or in heap?

    class Person
    {
    	private:
    		QString* name;
    		QList<QString*>* aliases;
    		QDate* birthday;
    		int children_number;
    
    	public:
    		Person(QString* name, QList<QString*>* aliases, QDate* birthday, const int &children_number);
    };
    
    1 Reply Last reply
    0
    • F Offline
      F Offline
      fcarney
      wrote on 7 Nov 2019, 20:27 last edited by
      #2
      int main(){
          Person person; // on stack
          Person* person2 = new Person(); // on heap
      }
      

      Whether or not the variables are on the heap or stack depends upon how the object is allocated. So all members of the class will be allocated how the object is allocated.

      C++ is a perfectly valid school of magic.

      E A 2 Replies Last reply 7 Nov 2019, 20:43
      1
      • F Offline
        F Offline
        fcarney
        wrote on 7 Nov 2019, 20:29 last edited by fcarney 11 Jul 2019, 20:29
        #3

        However, there is a limit to what you can allocate on the stack. So an object allocated on the stack may not be able to be allocated if its members are large.

        C++ is a perfectly valid school of magic.

        1 Reply Last reply
        0
        • F fcarney
          7 Nov 2019, 20:27
          int main(){
              Person person; // on stack
              Person* person2 = new Person(); // on heap
          }
          

          Whether or not the variables are on the heap or stack depends upon how the object is allocated. So all members of the class will be allocated how the object is allocated.

          E Offline
          E Offline
          Exotic_Devel
          wrote on 7 Nov 2019, 20:43 last edited by
          #4

          @fcarney

          Understand! In which case which of the two approaches I used as an example do you consider the best? And what is the reason?

          F 1 Reply Last reply 7 Nov 2019, 20:51
          0
          • F fcarney
            7 Nov 2019, 20:27
            int main(){
                Person person; // on stack
                Person* person2 = new Person(); // on heap
            }
            

            Whether or not the variables are on the heap or stack depends upon how the object is allocated. So all members of the class will be allocated how the object is allocated.

            A Offline
            A Offline
            aha_1980
            Lifetime Qt Champion
            wrote on 7 Nov 2019, 20:45 last edited by aha_1980 11 Jul 2019, 20:46
            #5

            @fcarney But note that almost all Qt objects consist of a public and a private part (the d-pointer). The private part is always on the heap, even if the corresponding object is on the stack.

            E.g.:

                QString s = "Hello world and a bit more of chars.";
                qDebug() << "sizeof(s) =" << sizeof(s) << "length(s) =" << s.length();
            

            returns: sizeof(s) = 8 length(s) = 36 on my machine, which means it takes 8 bytes stack and (36 + 1) * 2 byte heap for the actual data.

            Regards

            Edit: fixed mistake in the second sentence.

            Qt has to stay free or it will die.

            F 1 Reply Last reply 7 Nov 2019, 20:52
            4
            • E Exotic_Devel
              7 Nov 2019, 20:43

              @fcarney

              Understand! In which case which of the two approaches I used as an example do you consider the best? And what is the reason?

              F Offline
              F Offline
              fcarney
              wrote on 7 Nov 2019, 20:51 last edited by
              #6

              @Exotic_Devel said in Class properties in stack or heap?:

              which of the two approaches I used as an example do you consider the best

              It depends upon requirements. If you have an object generator that gives you items allocated on heap then a list of pointers is fine: QList<Object*> m_objList; for example. Doing dynamic allocation for the sake of dynamic allocation is not worthwhile. Keep things simple (ie QString name;) until you have a reason not to (int bigArray[] = new int[1000000000];). Consider using smart pointers as well.

              C++ is a perfectly valid school of magic.

              1 Reply Last reply
              2
              • A aha_1980
                7 Nov 2019, 20:45

                @fcarney But note that almost all Qt objects consist of a public and a private part (the d-pointer). The private part is always on the heap, even if the corresponding object is on the stack.

                E.g.:

                    QString s = "Hello world and a bit more of chars.";
                    qDebug() << "sizeof(s) =" << sizeof(s) << "length(s) =" << s.length();
                

                returns: sizeof(s) = 8 length(s) = 36 on my machine, which means it takes 8 bytes stack and (36 + 1) * 2 byte heap for the actual data.

                Regards

                Edit: fixed mistake in the second sentence.

                F Offline
                F Offline
                fcarney
                wrote on 7 Nov 2019, 20:52 last edited by
                #7

                @aha_1980 said in Class properties in stack or heap?:

                But note that almost all Qt objects consist of a public and a private part (the d-pointer).

                Sneaky sneaky Qt! Thanks for the tip!

                C++ is a perfectly valid school of magic.

                1 Reply Last reply
                1
                • C Offline
                  C Offline
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on 7 Nov 2019, 21:12 last edited by
                  #8

                  Just a nitpick - a QString does not use d-pointer implementation. That's something QObject derived classes do and QString is not one of them. The reason QString itself is small is that it's a variable sized container and the data it stores is resizable. You don't know the data size beforehand, so it requires dynamic reallocation.

                  Anyway - there's no point to have pointer members to container classes i.e. QString* or QList<>*. It makes the code harder to read, it makes unnecessary extra dynamic allocations (which is slow) and it makes accessing the data slow because of the double indirection through the pointers. In general if the objects are small (as in couple basic types) and they do the "heavy" data allocations just keep them as direct members, not pointers.

                  As for function parameters - if you don't modify the arguments simple types just pass by value i.e. just int instead of const int&. They fit in CPUs registers and adding references to them just makes it bigger and slower because of the indirection. For complex types (e.g. QString) always prefer const &. The const part is important because it conveys your function's interface i.e. clearly states that the function won't modify that parameter. As for pointer parameters - use them to express optionality - if you get a pointer you need to check if it's not null before you use it. With references you don't.

                  So by example, this is how you should "read" function arguments:

                  void func(Foo param) - function just takes a Foo, Foo is small (fits in registers) so it's better to pass it by value
                  void func(const Foo& param) - function just takes a Foo, Foo is not so small so we pass it via pointer (yes, references are just syntactic sugar for pointers)
                  void func(Foo& param) - function takes a Foo and modifies it
                  void func(Foo* param) - function can take a Foo but it works without it too, it can modify that Foo
                  void func(const Foo* param) - function can take a Foo but it works without it too, it won't modify that Foo

                  A E 2 Replies Last reply 8 Nov 2019, 07:49
                  5
                  • C Chris Kawa
                    7 Nov 2019, 21:12

                    Just a nitpick - a QString does not use d-pointer implementation. That's something QObject derived classes do and QString is not one of them. The reason QString itself is small is that it's a variable sized container and the data it stores is resizable. You don't know the data size beforehand, so it requires dynamic reallocation.

                    Anyway - there's no point to have pointer members to container classes i.e. QString* or QList<>*. It makes the code harder to read, it makes unnecessary extra dynamic allocations (which is slow) and it makes accessing the data slow because of the double indirection through the pointers. In general if the objects are small (as in couple basic types) and they do the "heavy" data allocations just keep them as direct members, not pointers.

                    As for function parameters - if you don't modify the arguments simple types just pass by value i.e. just int instead of const int&. They fit in CPUs registers and adding references to them just makes it bigger and slower because of the indirection. For complex types (e.g. QString) always prefer const &. The const part is important because it conveys your function's interface i.e. clearly states that the function won't modify that parameter. As for pointer parameters - use them to express optionality - if you get a pointer you need to check if it's not null before you use it. With references you don't.

                    So by example, this is how you should "read" function arguments:

                    void func(Foo param) - function just takes a Foo, Foo is small (fits in registers) so it's better to pass it by value
                    void func(const Foo& param) - function just takes a Foo, Foo is not so small so we pass it via pointer (yes, references are just syntactic sugar for pointers)
                    void func(Foo& param) - function takes a Foo and modifies it
                    void func(Foo* param) - function can take a Foo but it works without it too, it can modify that Foo
                    void func(const Foo* param) - function can take a Foo but it works without it too, it won't modify that Foo

                    A Offline
                    A Offline
                    aha_1980
                    Lifetime Qt Champion
                    wrote on 8 Nov 2019, 07:49 last edited by
                    #9

                    @Chris-Kawa

                    Chris Kawa Moderators about 11 hours ago

                    Just a nitpick - a QString does not use d-pointer implementation.

                    Then have a look here:

                    https://code.woboq.org/qt5/qtbase/src/corelib/text/qstring.h.html#QString::d

                    Regards

                    Qt has to stay free or it will die.

                    C 1 Reply Last reply 8 Nov 2019, 08:18
                    4
                    • A aha_1980
                      8 Nov 2019, 07:49

                      @Chris-Kawa

                      Chris Kawa Moderators about 11 hours ago

                      Just a nitpick - a QString does not use d-pointer implementation.

                      Then have a look here:

                      https://code.woboq.org/qt5/qtbase/src/corelib/text/qstring.h.html#QString::d

                      Regards

                      C Offline
                      C Offline
                      Chris Kawa
                      Lifetime Qt Champion
                      wrote on 8 Nov 2019, 08:18 last edited by
                      #10

                      @aha_1980 said

                      Then have a look here:

                      Haha, nice one :) I guess that's what I get for not being more clear.
                      The "d pointer" in Qt context usually refers to the Private implementation idiom (or PIMPL). QString does not use it and this is what I meant. It just happens to have a member called d becasue it refers to data.

                      1 Reply Last reply
                      3
                      • J Online
                        J Online
                        JonB
                        wrote on 8 Nov 2019, 08:29 last edited by
                        #11

                        @Chris-Kawa , @aha_1980
                        I'd like to know the difference for passing/receiving as function parameter between const QString and const QString&? They both involve passing (64-bit) 8 bytes, they both increment the shared usage of the of string in the allocation table, neither allows modification (copy-on-write). Right?

                        Actually, now I think about it, that's wrong, right? const QString& does not increment the reference count, right? And that's a big difference....

                        1 Reply Last reply
                        1
                        • C Offline
                          C Offline
                          Chris Kawa
                          Lifetime Qt Champion
                          wrote on 8 Nov 2019, 09:17 last edited by Chris Kawa 11 Aug 2019, 09:18
                          #12

                          Passing by const Foo calls copy constructor. Depending on a class this might be cheap or expensive. QString (and all implicitly shared Qt classes) have a mechanism that makes this copy not so expensive - it just copies data pointer and bumps a refcount. This is cheaper than copying whole data, but still more expensive than just copying a pointer when passing via const Foo&. In short - except for small types that don't involve any "copy logic" don't copy when you don't explicitly want a copy.

                          1 Reply Last reply
                          5
                          • C Chris Kawa
                            7 Nov 2019, 21:12

                            Just a nitpick - a QString does not use d-pointer implementation. That's something QObject derived classes do and QString is not one of them. The reason QString itself is small is that it's a variable sized container and the data it stores is resizable. You don't know the data size beforehand, so it requires dynamic reallocation.

                            Anyway - there's no point to have pointer members to container classes i.e. QString* or QList<>*. It makes the code harder to read, it makes unnecessary extra dynamic allocations (which is slow) and it makes accessing the data slow because of the double indirection through the pointers. In general if the objects are small (as in couple basic types) and they do the "heavy" data allocations just keep them as direct members, not pointers.

                            As for function parameters - if you don't modify the arguments simple types just pass by value i.e. just int instead of const int&. They fit in CPUs registers and adding references to them just makes it bigger and slower because of the indirection. For complex types (e.g. QString) always prefer const &. The const part is important because it conveys your function's interface i.e. clearly states that the function won't modify that parameter. As for pointer parameters - use them to express optionality - if you get a pointer you need to check if it's not null before you use it. With references you don't.

                            So by example, this is how you should "read" function arguments:

                            void func(Foo param) - function just takes a Foo, Foo is small (fits in registers) so it's better to pass it by value
                            void func(const Foo& param) - function just takes a Foo, Foo is not so small so we pass it via pointer (yes, references are just syntactic sugar for pointers)
                            void func(Foo& param) - function takes a Foo and modifies it
                            void func(Foo* param) - function can take a Foo but it works without it too, it can modify that Foo
                            void func(const Foo* param) - function can take a Foo but it works without it too, it won't modify that Foo

                            E Offline
                            E Offline
                            Exotic_Devel
                            wrote on 9 Nov 2019, 12:17 last edited by
                            #13

                            @Chris-Kawa said in Class properties in stack or heap?:

                            Anyway - there's no point to have pointer members to container classes i.e. QString* or QList<>*. It makes the code harder to read, it makes unnecessary extra dynamic allocations (which is slow) and it makes accessing the data slow because of the double indirection through the pointers.

                            Hello!

                            Does this apply to QMap as well?

                            J C 2 Replies Last reply 9 Nov 2019, 13:06
                            0
                            • E Exotic_Devel
                              9 Nov 2019, 12:17

                              @Chris-Kawa said in Class properties in stack or heap?:

                              Anyway - there's no point to have pointer members to container classes i.e. QString* or QList<>*. It makes the code harder to read, it makes unnecessary extra dynamic allocations (which is slow) and it makes accessing the data slow because of the double indirection through the pointers.

                              Hello!

                              Does this apply to QMap as well?

                              J Online
                              J Online
                              JonB
                              wrote on 9 Nov 2019, 13:06 last edited by JonB 11 Sept 2019, 14:30
                              #14

                              @Exotic_Devel
                              Yes, he's suggesting you should only bother to create QMap map variables, you don't need to go QMap *pMap = new QMap(). The QMap structure itself is small, it does not include the mapping table. This will apply to all the classes listed in https://doc.qt.io/qt-5/containers.html#the-container-classes (you'll see QMap there). Plus some others like QString, QByteArray and QVariant, but I don't know where you find a comprehensive list of those. See @Chris-Kawa's post below.

                              1 Reply Last reply
                              0
                              • E Exotic_Devel
                                9 Nov 2019, 12:17

                                @Chris-Kawa said in Class properties in stack or heap?:

                                Anyway - there's no point to have pointer members to container classes i.e. QString* or QList<>*. It makes the code harder to read, it makes unnecessary extra dynamic allocations (which is slow) and it makes accessing the data slow because of the double indirection through the pointers.

                                Hello!

                                Does this apply to QMap as well?

                                C Offline
                                C Offline
                                Chris Kawa
                                Lifetime Qt Champion
                                wrote on 9 Nov 2019, 14:21 last edited by
                                #15

                                @Exotic_Devel In the link I posted is a full list of implicitly shared classes: list of classes. What I said applies to all of them and yes, QMap is one of them.

                                1 Reply Last reply
                                3

                                7/15

                                7 Nov 2019, 20:52

                                • Login

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