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?
Forum Updated to NodeBB v4.3 + New Features

Class properties in stack or heap?

Scheduled Pinned Locked Moved Solved C++ Gurus
stackmemory
15 Posts 5 Posters 5.4k Views 3 Watching
  • 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.
  • fcarneyF fcarney
    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 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?

    fcarneyF 1 Reply Last reply
    0
    • fcarneyF fcarney
      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.

      aha_1980A Offline
      aha_1980A Offline
      aha_1980
      Lifetime Qt Champion
      wrote on last edited by aha_1980
      #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.

      fcarneyF 1 Reply Last reply
      4
      • E Exotic_Devel

        @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?

        fcarneyF Offline
        fcarneyF Offline
        fcarney
        wrote on 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
        • aha_1980A aha_1980

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

          fcarneyF Offline
          fcarneyF Offline
          fcarney
          wrote on 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
          • Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on 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

            aha_1980A E 2 Replies Last reply
            5
            • Chris KawaC Chris Kawa

              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

              aha_1980A Offline
              aha_1980A Offline
              aha_1980
              Lifetime Qt Champion
              wrote on 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.

              Chris KawaC 1 Reply Last reply
              4
              • aha_1980A aha_1980

                @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

                Chris KawaC Offline
                Chris KawaC Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on 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
                • JonBJ Online
                  JonBJ Online
                  JonB
                  wrote on 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
                  • Chris KawaC Offline
                    Chris KawaC Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on last edited by Chris Kawa
                    #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
                    • Chris KawaC Chris Kawa

                      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 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?

                      JonBJ Chris KawaC 2 Replies Last reply
                      0
                      • E Exotic_Devel

                        @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?

                        JonBJ Online
                        JonBJ Online
                        JonB
                        wrote on last edited by JonB
                        #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

                          @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?

                          Chris KawaC Offline
                          Chris KawaC Offline
                          Chris Kawa
                          Lifetime Qt Champion
                          wrote on 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

                          • Login

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