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. QListWidget::addItems() Data type question
Forum Updated to NodeBB v4.3 + New Features

QListWidget::addItems() Data type question

Scheduled Pinned Locked Moved Solved General and Desktop
33 Posts 6 Posters 5.4k Views 2 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.
  • Christian EhrlicherC Christian Ehrlicher

    @Binary91-0 said in QListWidget::addItems() Data type question:

    Does it ensure that the pointer will not point to another QTreeItem

    The const means, as already explained from others above, that the value is not modified inside the function.

    B Offline
    B Offline
    Binary91 0
    wrote on last edited by
    #22

    @Christian-Ehrlicher And the "value" in this example is the const pointer "this", right? So the only thing, the function guarantees is, that this pointer can't be changed, right? Does that mean, that the object it points to can be changed?

    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #23

      @Binary91-0 said in QListWidget::addItems() Data type question:

      that the object it points to can be changed?

      No, not in this case since the pointer itself is not const.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      B 1 Reply Last reply
      0
      • Christian EhrlicherC Christian Ehrlicher

        @Binary91-0 said in QListWidget::addItems() Data type question:

        that the object it points to can be changed?

        No, not in this case since the pointer itself is not const.

        B Offline
        B Offline
        Binary91 0
        wrote on last edited by Binary91 0
        #24

        @Christian-Ehrlicher Oh, I don't know what's wrong actually but I simply do not understand it.

        Look at this example that I found on my google research. It exactly explains this situation.

        There is written, that a "this"-pointer is a const pointer, hence T* const this.
        Now, in a const function, the object, this const pointer points to will also get const, hence const T* const this

        So why do you say that in this case, the pointer itsself was not const?

        Chris KawaC 1 Reply Last reply
        0
        • B Offline
          B Offline
          Binary91 0
          wrote on last edited by
          #25

          Sorry for double posting, but this may exceed the threads topic now.

          I created an example application with a test class to try all possible combinations of pointers and classic variables in const member functions and non-const member functions.

          class myQTest
          {
          private:
              int iPriv = 1, *iPPriv = nullptr;
              
              void fPriv();
          
          public:
              int iPub = 2, *iPPub = nullptr;
              
              myQTest();
              ~myQTest();
              void fPub1(int);
              void fPub2(int) const;
              void fPub3(int*);
              void fPub4(int*) const;
              void fPub5(int *const);
              void fPub6(int *const) const;
              void fPub7(const int);
              void fPub8(const int) const;
              void fPub9(const int*);
              void fPub10(const int*) const;
              void fPub11(const int *const);
              void fPub12(const int *const) const;
          };
          

          The first thing I realized is, that a "this"-pointer isn't const. So the explanation in the external link topic I mentioned above is either wrong or I missunderstood it.

          The second thing I do not understand is, that I can write the following code without compiler error:

          void myQTest::fPub3(int *const i) // The declaration was int*, NOT int const*!
          {
          
          }
          

          How is it possible to define this function with a const pointer to int although it was declared as a non-const pointer to int?

          Chris KawaC 2 Replies Last reply
          0
          • B Binary91 0

            @Christian-Ehrlicher Oh, I don't know what's wrong actually but I simply do not understand it.

            Look at this example that I found on my google research. It exactly explains this situation.

            There is written, that a "this"-pointer is a const pointer, hence T* const this.
            Now, in a const function, the object, this const pointer points to will also get const, hence const T* const this

            So why do you say that in this case, the pointer itsself was not const?

            Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by Chris Kawa
            #26

            @Binary91-0 I think it would be good to take a step back and go through it step by step, going back to your example:

            int TreeItem::row() const
            {
                if (m_parentItem)
                    return m_parentItem->m_childItems.indexOf(const_cast<TreeItem*>(this));
            
                return 0;
            }
            

            We're inside a const function, so this is of type const TreeItem*, so pointer to constant TreeItem.

            m_childItems is of type QVector<TreeItem*>, so vector's T in this case is TreeItem* - non-const pointer to non-const TreeItem.

            QVector has a int QVector::indexOf(const T & value, int from) const method, so substituting T it is:

            int QVector::indexOf(TreeItem * const & value, int from) const
            

            meaning it takes a reference to constant pointer to non-const TreeItem. The const on the function means it won't change any member of QVector. It has nothing to do with the parameter. And it makes sense, because finding an index of an item has no business modifying the container.

            Btw. const position in C++ syntax is a bit crazy so be careful not to fall into the trap. If you just naively replace T like this: const T& -> const TreeItem* & then you've done it wrong. This would give you a reference to non-const pointer to const TreeItem, which is not what is happening here. Look up the "east const vs west const" to have a peek at the war that is going on in the language lawyers world :)

            Ok, so we have a this pointer which is a non-const pointer to const TreeItem and we have a function that expects a reference to const pointer to non const TreeItem. We have two mismatches here - first is on the type of the pointer and the second is on the item. The first one is easy because, as we previously discussed ,const can be added implicitly. The second one needs to take const off the item, and, as we also discussed, this can't be done automatically, so a const_cast is required to take the const off.

            So to summarize:

            this                                    ->    const TreeItem*
            const_cast<TreeItem*>(this)             ->    TreeItem*
            indexOf(const_cast<TreeItem*>(this))    ->    TreeItem* const &
            

            that const in last type evaluation says that the function promises not to change the value of TreeItem*, so the pointer. It could, if it wanted, change the value of TreeItem or call a non-const members on it, but this is a generic container and it won't even know what T is, so it doesn't know T is a pointer and so it won't try to dereference that pointer.

            1 Reply Last reply
            1
            • B Binary91 0

              Sorry for double posting, but this may exceed the threads topic now.

              I created an example application with a test class to try all possible combinations of pointers and classic variables in const member functions and non-const member functions.

              class myQTest
              {
              private:
                  int iPriv = 1, *iPPriv = nullptr;
                  
                  void fPriv();
              
              public:
                  int iPub = 2, *iPPub = nullptr;
                  
                  myQTest();
                  ~myQTest();
                  void fPub1(int);
                  void fPub2(int) const;
                  void fPub3(int*);
                  void fPub4(int*) const;
                  void fPub5(int *const);
                  void fPub6(int *const) const;
                  void fPub7(const int);
                  void fPub8(const int) const;
                  void fPub9(const int*);
                  void fPub10(const int*) const;
                  void fPub11(const int *const);
                  void fPub12(const int *const) const;
              };
              

              The first thing I realized is, that a "this"-pointer isn't const. So the explanation in the external link topic I mentioned above is either wrong or I missunderstood it.

              The second thing I do not understand is, that I can write the following code without compiler error:

              void myQTest::fPub3(int *const i) // The declaration was int*, NOT int const*!
              {
              
              }
              

              How is it possible to define this function with a const pointer to int although it was declared as a non-const pointer to int?

              Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by Chris Kawa
              #27

              @Binary91-0 said:

              The first thing I realized is, that a "this"-pointer isn't const

              this is a prvalue. Yes, it's complicated, but one of the things it means is that, while you can't put a const (or volatile) on it, it is still non-modifiable, like nullptr or the result of built-in expressions. You can only assign it to stuff.

              To make it a little more confusing (because why not :P) some compilers (e.g. msvc and gcc in the past) implemented this as T* const in non-const methods and const T* const in const methods to ensure that non-modifiability, but that is not standard conforming and it kinda blew up when C++11 introduced r-value references. Oh well, it's a subtle corner case I guess.

              1 Reply Last reply
              1
              • B Binary91 0

                Sorry for double posting, but this may exceed the threads topic now.

                I created an example application with a test class to try all possible combinations of pointers and classic variables in const member functions and non-const member functions.

                class myQTest
                {
                private:
                    int iPriv = 1, *iPPriv = nullptr;
                    
                    void fPriv();
                
                public:
                    int iPub = 2, *iPPub = nullptr;
                    
                    myQTest();
                    ~myQTest();
                    void fPub1(int);
                    void fPub2(int) const;
                    void fPub3(int*);
                    void fPub4(int*) const;
                    void fPub5(int *const);
                    void fPub6(int *const) const;
                    void fPub7(const int);
                    void fPub8(const int) const;
                    void fPub9(const int*);
                    void fPub10(const int*) const;
                    void fPub11(const int *const);
                    void fPub12(const int *const) const;
                };
                

                The first thing I realized is, that a "this"-pointer isn't const. So the explanation in the external link topic I mentioned above is either wrong or I missunderstood it.

                The second thing I do not understand is, that I can write the following code without compiler error:

                void myQTest::fPub3(int *const i) // The declaration was int*, NOT int const*!
                {
                
                }
                

                How is it possible to define this function with a const pointer to int although it was declared as a non-const pointer to int?

                Chris KawaC Offline
                Chris KawaC Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on last edited by Chris Kawa
                #28

                @Binary91-0 said in QListWidget::addItems() Data type question:

                How is it possible to define this function with a const pointer to int although it was declared as a non-const pointer to int?

                The standard says that cv-qualifiers (const and volatile) of function parameters don't affect function type, meaning that you can drop const and volatile keywords in the declaration. IMO this is silly and unnecessary, but it doesn't harm anyone (apart from confusion and readability I guess). The interface says it might modify the parameter (no const in declaration) but it doesn't (const in definition).

                Btw. sorry for tripple posting. I wanted to answer each issue separately not to mix things up.

                1 Reply Last reply
                1
                • B Offline
                  B Offline
                  Binary91 0
                  wrote on last edited by Binary91 0
                  #29

                  First of all, thank you really much again for this detailed support. It made things much clearer!

                  We're inside a const function, so this is of type const TreeItem*, so pointer to constant TreeItem.

                  The const on the function means it won't change any member of QVector. It has nothing to do with the parameter. And it makes sense, because finding an index of an item has no business modifying the container.

                  Ok, this is clear for me now. The declaration of a member function to be const just tells the compiler to ensure that no object members are changed inside of it.

                  Btw. const position in C++ syntax is a bit crazy so be careful not to fall into the trap. If you just naively replace T like this: const T& -> const TreeItem* & then you've done it wrong. This would give you a reference to non-const pointer to const TreeItem, which is not what is happening here. Look up the "east const vs west const" to have a peek at the war that is going on in the language lawyers world :)

                  That's it! Thank you so much! This was the main thing I did not understand. But after thinking about it, it makes sense. The function wants to tell the user that the "thing" he passes to it will be const. By passing a pointer, hence the pointer will be const.

                  Ok, so we have a this pointer which is a non-const pointer to const TreeItem and we have a function that expects a reference to const pointer to non const TreeItem. We have two mismatches here - first is on the type of the pointer and the second is on the item.

                  The first one is easy because, as we previously discussed ,const can be added implicitly.

                  What do you mean with "implicitly"? Do you mean that the compiler does an implicit type conversion of T to T const because we call the function by reference? If yes, then compiler had to do a re-conversion back to non-const after returning from the function to ensure not to have changed the source, right? What I mean: Will the source (i.e. the QTreeItem*) be re-declared as a QTreeItem *const inside the function body as I call it by reference or is it again just a hint for the compiler to handle the non-const QTreeItem pointer as a const pointer without "really/physically" changing anything of the source/source type?

                  What would happen in a call-by-value condition? As it is possible to copy variables or pointers of the same type T into variables or pointers of type T const, it should be no problem at all, right? In this case, compiler shouldn't have to do any "implicit type conversions" as there will only be a copy created. On the other hand, in a call-by-value condition, I can't see any sense in declaring the function parameter as const, because no changes can be done to the origin source, right? (This is just for me to see if I slowly get the point of this stuff or if I'm still far away from understanding the usability of using const and call-by-ref vs non-const and call-by-val).

                  The standard says that cv-qualifiers (const and volatile) of function parameters don't affect function type, meaning that you can drop const and volatile keywords in the declaration.

                  Interestingly, I can't do this arbitrary adding of "const" in every of the functions mentioned above.
                  Origin:

                  void myQTest::fPub1(int i)
                  {
                  }
                  
                  void myQTest::fPub3(int *i)
                  {
                  }
                  

                  These definition changes are possible:

                  void myQTest::fPub1(const int i)
                  {
                  }
                  
                  void myQTest::fPub3(int *const i)
                  {
                  }
                  

                  But this one gives a compiler error:

                  void myQTest::fPub3(const int *i)
                  {
                  }
                  

                  As I know now, that const can be added "arbitrarily", I wonder why the last example dosn't work. I mean, it is possible to initialize a non-const pointer to a const int with a non-const pointer to a non-const int, because the following code works:

                      int i1 = 1;
                      int *iP1 = &i1;
                      int const *icP1 = iP1;
                  

                  What's the reason for this behavior?

                  Chris KawaC 1 Reply Last reply
                  0
                  • B Binary91 0

                    First of all, thank you really much again for this detailed support. It made things much clearer!

                    We're inside a const function, so this is of type const TreeItem*, so pointer to constant TreeItem.

                    The const on the function means it won't change any member of QVector. It has nothing to do with the parameter. And it makes sense, because finding an index of an item has no business modifying the container.

                    Ok, this is clear for me now. The declaration of a member function to be const just tells the compiler to ensure that no object members are changed inside of it.

                    Btw. const position in C++ syntax is a bit crazy so be careful not to fall into the trap. If you just naively replace T like this: const T& -> const TreeItem* & then you've done it wrong. This would give you a reference to non-const pointer to const TreeItem, which is not what is happening here. Look up the "east const vs west const" to have a peek at the war that is going on in the language lawyers world :)

                    That's it! Thank you so much! This was the main thing I did not understand. But after thinking about it, it makes sense. The function wants to tell the user that the "thing" he passes to it will be const. By passing a pointer, hence the pointer will be const.

                    Ok, so we have a this pointer which is a non-const pointer to const TreeItem and we have a function that expects a reference to const pointer to non const TreeItem. We have two mismatches here - first is on the type of the pointer and the second is on the item.

                    The first one is easy because, as we previously discussed ,const can be added implicitly.

                    What do you mean with "implicitly"? Do you mean that the compiler does an implicit type conversion of T to T const because we call the function by reference? If yes, then compiler had to do a re-conversion back to non-const after returning from the function to ensure not to have changed the source, right? What I mean: Will the source (i.e. the QTreeItem*) be re-declared as a QTreeItem *const inside the function body as I call it by reference or is it again just a hint for the compiler to handle the non-const QTreeItem pointer as a const pointer without "really/physically" changing anything of the source/source type?

                    What would happen in a call-by-value condition? As it is possible to copy variables or pointers of the same type T into variables or pointers of type T const, it should be no problem at all, right? In this case, compiler shouldn't have to do any "implicit type conversions" as there will only be a copy created. On the other hand, in a call-by-value condition, I can't see any sense in declaring the function parameter as const, because no changes can be done to the origin source, right? (This is just for me to see if I slowly get the point of this stuff or if I'm still far away from understanding the usability of using const and call-by-ref vs non-const and call-by-val).

                    The standard says that cv-qualifiers (const and volatile) of function parameters don't affect function type, meaning that you can drop const and volatile keywords in the declaration.

                    Interestingly, I can't do this arbitrary adding of "const" in every of the functions mentioned above.
                    Origin:

                    void myQTest::fPub1(int i)
                    {
                    }
                    
                    void myQTest::fPub3(int *i)
                    {
                    }
                    

                    These definition changes are possible:

                    void myQTest::fPub1(const int i)
                    {
                    }
                    
                    void myQTest::fPub3(int *const i)
                    {
                    }
                    

                    But this one gives a compiler error:

                    void myQTest::fPub3(const int *i)
                    {
                    }
                    

                    As I know now, that const can be added "arbitrarily", I wonder why the last example dosn't work. I mean, it is possible to initialize a non-const pointer to a const int with a non-const pointer to a non-const int, because the following code works:

                        int i1 = 1;
                        int *iP1 = &i1;
                        int const *icP1 = iP1;
                    

                    What's the reason for this behavior?

                    Chris KawaC Offline
                    Chris KawaC Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on last edited by Chris Kawa
                    #30

                    What do you mean with "implicitly"? Do you mean that the compiler does an implicit type conversion of T to T const because we call the function by reference? If yes, then compiler had to do a re-conversion back to non-const after returning from the function to ensure not to have changed the source, right?

                    I thought we already covered that before? No, compiler does not change the source code and it does not change the meaning of your variables. It just manages memory blocks with language provided attributes (like const). Consider this example:

                    int variable;  //1
                    
                    void Foo(int& a) { }
                    void Bar(const int& b) { }
                    void Bazz(int c) { }
                    
                    Foo(variable);  //2
                    Bar(variable);  //3
                    Bazz(variable); //4
                    

                    This is basically what the compiler is doing (not really, but you can think about it this way if you don't want to go into detail on Abstract Syntax Trees):

                    • //1 Lets reserve 32bits of memory at address 0x1234 and refer to that memory as variable. Whenever we refer to variable we can read or write from the memory it names.
                    • //2 Lets jump to code pointed by a function named Foo
                      Lets take the memory named variable and now call it a. We can read and write to memory named a.
                      Lets jump back out to where we were before.
                    • //3 Lets jump to code pointed by a function named Bar
                      Lets take the memory named variable and now call it b. We can only read from memory named b and any write access made through that b name will be a compile error.
                      Lets jump back out to where we were before.
                    • //4 Lets jump to code pointed by a function named Bazz
                      Lets reserve 32bit of memory at address 0x5678 and call it c. We can read and write to memory named c.
                      Lets copy 32bits from memory named variable to memory named c.
                      Lets jump back out to where we were before.

                    in a call-by-value condition, I can't see any sense in declaring the function parameter as const, because no changes can be done to the origin source, right?

                    Yes, there's pretty much no point in declaring by-value params as const. It does prevent the function from changing the value inside, but the caller doesn't care, because it's not his variable that gets modified so it's basically just a documentation of the internal implementation. Some might consider this a bad practice because of that reason.

                    As I know now, that const can be added "arbitrarily"

                    It's not arbitrary. Basically you can differ in declaration/definition on how the parameter is passed to the function, not on the type of the parameter itself. In other words:
                    int * -> int* const : changes non const "something" to const "something", that's ok
                    int *-> const int* : changes non-const "something" to non-const "something else", that's not allowed.

                    Anyway, let me be on the record that it's an obscure language quirk and I strongly discourage you to do that in practice. Keep it simple, make life of other programmers reading your code easier and make your declarations and definitions match.

                    1 Reply Last reply
                    2
                    • Chris KawaC Offline
                      Chris KawaC Offline
                      Chris Kawa
                      Lifetime Qt Champion
                      wrote on last edited by
                      #31

                      As an interesting side note about those a,b,c variables - as you can see all it does is it kinda attaches read or write modifiers to some symbolic names. When you create a new name (the parameter of a function) it gets its own set of modifiers and doesn't affect the name it got created from. You can actually never change those attributes for a given name. You can only create a new name with different set of attributes that names the same data.

                      This is also the reason why const_cast is so dangerous. What it does is:

                      const int a = 42;
                      int& b = const_cast<int>(a);
                      

                      Memory referred by name a will never be written to. Memory referred by name b can be written to. Everything is fine, nothing to look at. But hey, guess what - both names name the same memory block, so if compiler made some assumptions based on that a declaration, like, for example, placed it in a read only memory of the device, you're in trouble.

                      Sometimes, like in the Qt example, const_cast is just a hacky workaround for some interface and if you don't actually use that variable to write it will be fine, but sometimes it can silently blow up and then it's a bad day at work. So use it sparingly and try to design your interfaces in a way that won't require const casts (I'm looking at you QAbstractItemDelegate::createEditor :) ).

                      1 Reply Last reply
                      2
                      • B Offline
                        B Offline
                        Binary91 0
                        wrote on last edited by Binary91 0
                        #32

                        I thought we already covered that before? No, compiler does not change the source code and it does not change the meaning of your variables. It just manages memory blocks with language provided attributes (like const).

                        Sure, but I didn't understand how compiler is internally handling this. As I see, in a call-by-ref-condition, a reference to my source is created and const-attributed. This ensures that whatever I passed to the function, it will be not changed. If it was a variable, then its contents are safe. If it was a pointer, then the pointer itsself is safe, but its dereferencing stuff can be edited.
                        In a call-by-value-condition, new variables are physically created with corresponding new memory space. Therefore, no const attribute is needed, cause the source variable will never be reachable for the function.

                        As an interesting side note about those a,b,c variables - as you can see all it does is it kinda attaches read or write modifiers to some symbolic names. [...] You can actually never change those attributes for a given name. You can only create a new name with different set of attributes that names the same data.

                        So you mean, inside the function, it would not be possible to change the attribute of a function parameter? Is that behaviour different of "normal" variables other than function parameters?

                        When you create a new name (the parameter of a function) it gets its own set of modifiers and doesn't affect the name it got created from.

                        You mean that declaring a function argument e.g. as const does not affect the origin source variable which I pass to the function, right? Yes, that was one thing I had to internalize. I thought that by handling references, everything will affect the source variable.

                        It's not arbitrary. Basically you can differ in declaration/definition on how the parameter is passed to the function, not on the type of the parameter itself. In other words:
                        int * -> int* const : changes non const "something" to const "something", that's ok
                        int -> const int : changes non-const "something" to non-const "something else", that's not allowed.

                        This is what I'm still trying to comprehend, because the following code works just fine:

                            int i1 = 1;
                            int *iP1 = &i1;
                            int const *icP1 = iP1;
                        

                        Here, I initialize a int const* with a int* and it works. In the function call, it doesn't work.

                        Memory referred by name a will never be written to. Memory referred by name b can be written to. Everything is fine, nothing to look at. But hey, guess what - both names name the same memory block, so if compiler made some assumptions based on that a declaration, like, for example, placed it in a read only memory of the device, you're in trouble.

                        Haha, I see, this is very dangerous! I'm asking myself whether there is a way to tell compiler like in a forward declaration that this variable may be kind of mutable so it will be never stored in a read-only memory part of the device...

                        I am sorry for all those questions, I think I could already profit a lot from your great support and I simultaniously do a google recherche for all of this, but it's pretty difficult to find good matching answers to this "specific" questions.
                        If you can recommend any literature to that, I would really appreciate that.

                        1 Reply Last reply
                        0
                        • Christian EhrlicherC Offline
                          Christian EhrlicherC Offline
                          Christian Ehrlicher
                          Lifetime Qt Champion
                          wrote on last edited by
                          #33

                          @Binary91-0 said in QListWidget::addItems() Data type question:

                          In the function call, it doesn't work.

                          You don't do this in the function call (as I already said) - you do

                          const TreeItem *myItem = this;
                          TreeItem *myNonConstItem = myItem;
                          

                          And, as I already told you, is not allowed since this would kill the whole idea of const.

                          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                          Visit the Qt Academy at https://academy.qt.io/catalog

                          1 Reply Last reply
                          1

                          • Login

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