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. Return pointer-to-member in const method
Forum Updated to NodeBB v4.3 + New Features

Return pointer-to-member in const method

Scheduled Pinned Locked Moved Solved C++ Gurus
35 Posts 6 Posters 8.6k Views 6 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.
  • JonBJ JonB
    class Foo
    {
        int member;
        int *pointerToMember() const { return &member; }
    }
    

    gcc 9.3.0:

    error: cannot initialize return object of type 'int *' with an rvalue of type 'const int *'

    The declaration of the method as const prevents me returning &member. I might use that pointer later (code here is simplest, not real example) for write access to member, so I don't want to return const int *, but this method itself does not alter member.

    Could someone explain what this rule is on a const class method? If possible, can you supply a C++ reference page on this aspect of const so I can read up? Thanks.

    jsulmJ Offline
    jsulmJ Offline
    jsulm
    Lifetime Qt Champion
    wrote on last edited by
    #2

    @JonB said in Return pointer-to-member in const method:

    int *pointerToMember() const { return &member; }

    const int *pointerToMember() const { return &member; }
    

    Else you would be able to change the state of the object using the pointer even though the method is marked as const.

    https://forum.qt.io/topic/113070/qt-code-of-conduct

    JonBJ 1 Reply Last reply
    4
    • jsulmJ jsulm

      @JonB said in Return pointer-to-member in const method:

      int *pointerToMember() const { return &member; }

      const int *pointerToMember() const { return &member; }
      

      Else you would be able to change the state of the object using the pointer even though the method is marked as const.

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #3

      @jsulm
      But I know this, which is why I wrote

      so I don't want to return const int *, but this method itself does not alter member

      I was asking (nicely) if you have a reference to this aspect of const method in C++ I could read up on? I do understand a const method cannot alter a member, but in itself this method does not do so.

      Let me try this: sometimes I use this return result just for read, sometimes I want to write back into the pointed-to. Obviously if I just remove the const off the method, I cannot call it in the read-only case from some other class const method.

      How to achieve? Do I have to provide two methods:

      int *pointerToMember() { return &member; }
      const int *pointerToMember() const { return &member; }
      

      I have a feeling you may answer "yes" to that?

      Supposing you do: assume the body of the method is several lines long. [For the record, it's actually a look-up in a member array of structs, and I want to return a pointer to the found element/nullptr, not an index.] So I do not want to have to re-write the code in each of these two methods. How can I write it only once? I'm going to have trouble if my non-const overload tries to call the const overload, or if the const overload tries to call the non-const one, either way, aren't I?

      jsulmJ 1 Reply Last reply
      0
      • JonBJ JonB

        @jsulm
        But I know this, which is why I wrote

        so I don't want to return const int *, but this method itself does not alter member

        I was asking (nicely) if you have a reference to this aspect of const method in C++ I could read up on? I do understand a const method cannot alter a member, but in itself this method does not do so.

        Let me try this: sometimes I use this return result just for read, sometimes I want to write back into the pointed-to. Obviously if I just remove the const off the method, I cannot call it in the read-only case from some other class const method.

        How to achieve? Do I have to provide two methods:

        int *pointerToMember() { return &member; }
        const int *pointerToMember() const { return &member; }
        

        I have a feeling you may answer "yes" to that?

        Supposing you do: assume the body of the method is several lines long. [For the record, it's actually a look-up in a member array of structs, and I want to return a pointer to the found element/nullptr, not an index.] So I do not want to have to re-write the code in each of these two methods. How can I write it only once? I'm going to have trouble if my non-const overload tries to call the const overload, or if the const overload tries to call the non-const one, either way, aren't I?

        jsulmJ Offline
        jsulmJ Offline
        jsulm
        Lifetime Qt Champion
        wrote on last edited by
        #4

        @JonB said in Return pointer-to-member in const method:

        How can I write it only once?

        You can call the const version in non-const version and const_cast the return value from the const version. const_cast should of course be avoided, but in your scenario I think it is OK.

        const int *pointerToMemberConst() const { return &member; }
        int *pointerToMember()  { return const_cast<int*>(pointerToMemberConst()); }
        

        I don't have a good source for this topic at hand.

        https://forum.qt.io/topic/113070/qt-code-of-conduct

        JonBJ 1 Reply Last reply
        1
        • jsulmJ jsulm

          @JonB said in Return pointer-to-member in const method:

          How can I write it only once?

          You can call the const version in non-const version and const_cast the return value from the const version. const_cast should of course be avoided, but in your scenario I think it is OK.

          const int *pointerToMemberConst() const { return &member; }
          int *pointerToMember()  { return const_cast<int*>(pointerToMemberConst()); }
          

          I don't have a good source for this topic at hand.

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by JonB
          #5

          @jsulm
          Yes, and thank you, that was all I could think of doing myself, that way round. It's just that borrowing from @Chris-Kawa over at https://forum.qt.io/topic/120328/std-vector-qvector-and-fields/11, his

          and a cute fluffy kitten will gruesomely die somewhere every time you do that :(

          applies to (de-)const-casting ;-)

          jsulmJ 1 Reply Last reply
          0
          • JonBJ JonB

            @jsulm
            Yes, and thank you, that was all I could think of doing myself, that way round. It's just that borrowing from @Chris-Kawa over at https://forum.qt.io/topic/120328/std-vector-qvector-and-fields/11, his

            and a cute fluffy kitten will gruesomely die somewhere every time you do that :(

            applies to (de-)const-casting ;-)

            jsulmJ Offline
            jsulmJ Offline
            jsulm
            Lifetime Qt Champion
            wrote on last edited by
            #6

            @JonB Add a "goto" to make him even more "happy" :-)

            https://forum.qt.io/topic/113070/qt-code-of-conduct

            JonBJ 1 Reply Last reply
            1
            • jsulmJ jsulm

              @JonB Add a "goto" to make him even more "happy" :-)

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by JonB
              #7

              @jsulm
              OK, we're nearly there, but we have a wrinkle.

              I want these two methods to have the same name. So I don't want the Const suffix on the const one.

              I am assuming we can do this in C++, because Qt has methods like QVector:

              T &	operator[](int i)
              const T &	operator[](int i) const
              

              (I know that's an operator, but I think if I looked around there are other methods which have both const & non-const variants?)

              So I try:

              const int *pointerToMember() const { return &member; }
              int *pointerToMember()  { return const_cast<int*>(pointerToMember()); }
              

              But the second overload gives Creator yellow-triangle clang warning

              warning: all paths through this function will call itself

              gcc compiles without warning. But when I test at run-time, sure enough, I get infinite recursion: the second overload calls itself, not the first one, and I am foo-barred :(

              So.... Qt seems to manage with same-named const & non-const variants. How can I adapt your suggestion, so they use common code yet work as required, please? E.g. is there anything I can write here to make the second overload's pointerToMember() call the first one, not itself, some "overloadOf" or something?

              EDIT
              I guess I could do:

              private:
                  const int *_pointerToMember() const { return &member; }
              
              public:
                  const int *pointerToMember() const { return _pointerToMember(); }
                  int *pointerToMember()  { return const_cast<int*>(_pointerToMember()); }
              

              Can I do it without that extra dummy method? Neater, and guaranteed [don't start on me with inline ;-) ] not to have an inefficient extra function call :)

              jsulmJ 1 Reply Last reply
              0
              • JonBJ JonB

                @jsulm
                OK, we're nearly there, but we have a wrinkle.

                I want these two methods to have the same name. So I don't want the Const suffix on the const one.

                I am assuming we can do this in C++, because Qt has methods like QVector:

                T &	operator[](int i)
                const T &	operator[](int i) const
                

                (I know that's an operator, but I think if I looked around there are other methods which have both const & non-const variants?)

                So I try:

                const int *pointerToMember() const { return &member; }
                int *pointerToMember()  { return const_cast<int*>(pointerToMember()); }
                

                But the second overload gives Creator yellow-triangle clang warning

                warning: all paths through this function will call itself

                gcc compiles without warning. But when I test at run-time, sure enough, I get infinite recursion: the second overload calls itself, not the first one, and I am foo-barred :(

                So.... Qt seems to manage with same-named const & non-const variants. How can I adapt your suggestion, so they use common code yet work as required, please? E.g. is there anything I can write here to make the second overload's pointerToMember() call the first one, not itself, some "overloadOf" or something?

                EDIT
                I guess I could do:

                private:
                    const int *_pointerToMember() const { return &member; }
                
                public:
                    const int *pointerToMember() const { return _pointerToMember(); }
                    int *pointerToMember()  { return const_cast<int*>(_pointerToMember()); }
                

                Can I do it without that extra dummy method? Neater, and guaranteed [don't start on me with inline ;-) ] not to have an inefficient extra function call :)

                jsulmJ Offline
                jsulmJ Offline
                jsulm
                Lifetime Qt Champion
                wrote on last edited by
                #8

                @JonB It's getting ugly :-)

                const int *pointerToMember() const { return &member; }
                int *pointerToMember()  { const MyClass *_this = this;  return const_cast<int*>(_this->pointerToMember()); } // Now compiler knows that you want to call const pointerToMember
                

                https://forum.qt.io/topic/113070/qt-code-of-conduct

                JonBJ 3 Replies Last reply
                4
                • jsulmJ jsulm

                  @JonB It's getting ugly :-)

                  const int *pointerToMember() const { return &member; }
                  int *pointerToMember()  { const MyClass *_this = this;  return const_cast<int*>(_this->pointerToMember()); } // Now compiler knows that you want to call const pointerToMember
                  
                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by JonB
                  #9

                  @jsulm
                  Hmm, good one, thanks! Now I have an extra assignment to slow my code down :( ;-)

                  This is indeed fine, and I get it. Nonetheless, final question: is there something in C++ to do with like "overload of" which can pick between the const & non-const variants here? Just because I am interested. You know that when we use Qt connect() we can use QOverload<...>::of to pick desired function overloads, I have a feeling that resolves to some C++ "overload of" statement? But here we are trying to distinguish between signatures which do not differ in parameters, I'm trying to understand whether that can be done?

                  1 Reply Last reply
                  0
                  • fcarneyF Offline
                    fcarneyF Offline
                    fcarney
                    wrote on last edited by
                    #10
                    const auto value1 = obj->pointerToMember(); // should be const version
                    auto value2 = obj->pointerToMember(); // should be non-const version
                    

                    C++ is a perfectly valid school of magic.

                    JonBJ 1 Reply Last reply
                    0
                    • fcarneyF fcarney
                      const auto value1 = obj->pointerToMember(); // should be const version
                      auto value2 = obj->pointerToMember(); // should be non-const version
                      
                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by JonB
                      #11

                      @fcarney

                          const int *pointerToMember() const { ... }
                          int *pointerToMember()  { ... }
                      
                      const auto value1 = obj->pointerToMember(); // should be const version
                      

                      Nope (but thanks for your interest!), that const one steps straight into the second, non-const variant! (As does the other call too.)

                      I would not expect const variable = method() to call the const variant of the method, particularly. So far as I know, that const on the variable perfectly allows it to pick any non-const method, it only chooses to treat the return result as const but no other effect. Which is what it does it here.

                      1 Reply Last reply
                      1
                      • fcarneyF Offline
                        fcarneyF Offline
                        fcarney
                        wrote on last edited by
                        #12

                        Interesting, maybe don't overload then. I tried as reference to see if it makes a difference. No change.

                        C++ is a perfectly valid school of magic.

                        1 Reply Last reply
                        0
                        • jsulmJ jsulm

                          @JonB It's getting ugly :-)

                          const int *pointerToMember() const { return &member; }
                          int *pointerToMember()  { const MyClass *_this = this;  return const_cast<int*>(_this->pointerToMember()); } // Now compiler knows that you want to call const pointerToMember
                          
                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by JonB
                          #13

                          @jsulm said in Return pointer-to-member in const method:

                          int *pointerToMember()  { const MyClass *_this = this;  return const_cast<int*>(_this->pointerToMember()); } // Now compiler knows that you want to call const pointerToMember
                          

                          I wrote

                          Now I have an extra assignment to slow my code down :( ;-)

                          So I adapted, to remove _this:

                          int *pointerToMember()  { return const_cast<int*>( const_cast<const MyClass *>(this)->pointerToMember() ); }
                          

                          I prefer yours for readability :)

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

                            I left you for one minute and there's const_cast and goto :P

                            Getting back to original problem. At first glance you could do something like this:

                            class Foo
                            {
                            private:
                                std::array<Stuff, 42> data;
                                int indexOf(Key key) const { return /* some lengthy way to determine the index */; };
                             
                            public:
                                Stuff* get(Key key) { int index = indexOf(key); return (index < 0) ? nullptr : &data[index]; }
                                const Stuff* get(Key key) const { int index = indexOf(key); return (index < 0) ? nullptr : &data[index]; }
                            };
                            

                            no casts but I would argue that this is a patch work. The solution becomes a lot nicer if you dig into the problem, which is you're trying to pack two things into one getter - a logic to determine if given element is present and retrieving it. Those are two things and they also incur a performance cost (branching) so I'd say design your interface so that the decision about taking the cost or not is left to the user of your class:

                            class Bar
                            {
                            private:
                                std::array<Stuff, 42> data;
                                
                            public:
                                int indexOf(Key key) const { return /* some lengthy way to determine the index */; };
                                Stuff& at(int index) { return data[index]; }
                                const Stuff& at(int index) const { return data[index]; }
                            };
                            

                            Shorter, easier, faster and class doesn't absorb responsibilities it doesn't need to. Also those at methods will most definitely get inlined and disappear (inlining is real and super important, don't dismiss it :) )

                            As for the other thing:

                            const auto value1 = obj->pointerToMember(); // should be const version
                            auto value2 = obj->pointerToMember(); // should be non-const version

                            const or non-const is determined by the constness of the object it is called on, not unrelated variable the result is assigned to, so:

                            auto value1 = const_obj->pointerToMember(); // const version, auto resolves to const something
                            auto value2 = obj->pointerToMember(); // non-const version, auto resolves to non-const something
                            

                            Btw. this is a source of a common performance trap with Qt and C++11:

                            QVector<Stuff> stuff;
                            
                            for (Stuff& foo : stuff) {}  //no! calls non-const begin/end and can cause expensive detach()
                            

                            so people think "oh, I should just add const and it's fine":

                            for (const Stuff& foo : stuff) {}  //no! still calls non-const begin/end
                            

                            The proper way to do it is:

                            for (const Stuff& foo : qAsConst(stuff)) {}  //ok, calls const begin/end
                            
                            JonBJ 1 Reply Last reply
                            5
                            • Chris KawaC Chris Kawa

                              I left you for one minute and there's const_cast and goto :P

                              Getting back to original problem. At first glance you could do something like this:

                              class Foo
                              {
                              private:
                                  std::array<Stuff, 42> data;
                                  int indexOf(Key key) const { return /* some lengthy way to determine the index */; };
                               
                              public:
                                  Stuff* get(Key key) { int index = indexOf(key); return (index < 0) ? nullptr : &data[index]; }
                                  const Stuff* get(Key key) const { int index = indexOf(key); return (index < 0) ? nullptr : &data[index]; }
                              };
                              

                              no casts but I would argue that this is a patch work. The solution becomes a lot nicer if you dig into the problem, which is you're trying to pack two things into one getter - a logic to determine if given element is present and retrieving it. Those are two things and they also incur a performance cost (branching) so I'd say design your interface so that the decision about taking the cost or not is left to the user of your class:

                              class Bar
                              {
                              private:
                                  std::array<Stuff, 42> data;
                                  
                              public:
                                  int indexOf(Key key) const { return /* some lengthy way to determine the index */; };
                                  Stuff& at(int index) { return data[index]; }
                                  const Stuff& at(int index) const { return data[index]; }
                              };
                              

                              Shorter, easier, faster and class doesn't absorb responsibilities it doesn't need to. Also those at methods will most definitely get inlined and disappear (inlining is real and super important, don't dismiss it :) )

                              As for the other thing:

                              const auto value1 = obj->pointerToMember(); // should be const version
                              auto value2 = obj->pointerToMember(); // should be non-const version

                              const or non-const is determined by the constness of the object it is called on, not unrelated variable the result is assigned to, so:

                              auto value1 = const_obj->pointerToMember(); // const version, auto resolves to const something
                              auto value2 = obj->pointerToMember(); // non-const version, auto resolves to non-const something
                              

                              Btw. this is a source of a common performance trap with Qt and C++11:

                              QVector<Stuff> stuff;
                              
                              for (Stuff& foo : stuff) {}  //no! calls non-const begin/end and can cause expensive detach()
                              

                              so people think "oh, I should just add const and it's fine":

                              for (const Stuff& foo : stuff) {}  //no! still calls non-const begin/end
                              

                              The proper way to do it is:

                              for (const Stuff& foo : qAsConst(stuff)) {}  //ok, calls const begin/end
                              
                              JonBJ Offline
                              JonBJ Offline
                              JonB
                              wrote on last edited by JonB
                              #15

                              @Chris-Kawa said in Return pointer-to-member in const method:

                              I left you for one minute and there's const_cast and goto :P

                              That's what happens to fluffy kittens if you turn your back....

                              Let's pick my one of what (I understand) you suggest:

                                  int indexOf(Key key) const { return /* some lengthy way to determine the index */; };
                                  Stuff& at(int index) { return data[index]; }
                                  const Stuff& at(int index) const { return data[index]; }
                              

                              So, you avoid the problem by making the lookup function return an int index. Then you return const/non-const data[index].

                              This breaks my (unspoken) "efficiency" criterion! My lookup marches through the array without an int counter, only with a pointer (it can return nullptr on not-found, so no references here), and returns that. You will make me turn that into an index, and then you will turn it back by adding it onto data.

                              I am shocked. I was speaking to someone recently in another thread here, and they berated me for the overhead of indexing into arrays, when I said it was "milliseconds" they said "every microsecond counts, in game development, this is not to be ignored". Can you think who that was? :D

                              Chris KawaC 1 Reply Last reply
                              0
                              • JonBJ JonB

                                @Chris-Kawa said in Return pointer-to-member in const method:

                                I left you for one minute and there's const_cast and goto :P

                                That's what happens to fluffy kittens if you turn your back....

                                Let's pick my one of what (I understand) you suggest:

                                    int indexOf(Key key) const { return /* some lengthy way to determine the index */; };
                                    Stuff& at(int index) { return data[index]; }
                                    const Stuff& at(int index) const { return data[index]; }
                                

                                So, you avoid the problem by making the lookup function return an int index. Then you return const/non-const data[index].

                                This breaks my (unspoken) "efficiency" criterion! My lookup marches through the array without an int counter, only with a pointer (it can return nullptr on not-found, so no references here), and returns that. You will make me turn that into an index, and then you will turn it back by adding it onto data.

                                I am shocked. I was speaking to someone recently in another thread here, and they berated me for the overhead of indexing into arrays, when I said it was "milliseconds" they said "every microsecond counts, in game development, this is not to be ignored". Can you think who that was? :D

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

                                @JonB said:

                                Can you think who that was? :D

                                Yup, and I stand by what I said, which was not indexing into an array but indexing into a vector. Huge huge difference.

                                The int index is just an example. Every case is different and it doesn't have to be an int. It could be an iterator, some hash thingie or whatever is most efficient in your case. Pointer has that nasty proprty of being both index and data at the same time, which causes your problems - you want a const pointy thing and a non-const data thing. One variable can't be both at the same time so that's why I'm suggesting to split them up.

                                JonBJ 1 Reply Last reply
                                2
                                • Chris KawaC Chris Kawa

                                  @JonB said:

                                  Can you think who that was? :D

                                  Yup, and I stand by what I said, which was not indexing into an array but indexing into a vector. Huge huge difference.

                                  The int index is just an example. Every case is different and it doesn't have to be an int. It could be an iterator, some hash thingie or whatever is most efficient in your case. Pointer has that nasty proprty of being both index and data at the same time, which causes your problems - you want a const pointy thing and a non-const data thing. One variable can't be both at the same time so that's why I'm suggesting to split them up.

                                  JonBJ Offline
                                  JonBJ Offline
                                  JonB
                                  wrote on last edited by JonB
                                  #17

                                  @Chris-Kawa

                                  int indexOf(Key key) const { return /* some lengthy way to determine the index */; };
                                  

                                  The problem here is, that function returning int does not exhibit the problem! You don't have to worry about returning int versus const int. It's when function returns a something *. int method() const is never a problem, but int *method() const where it returns a member variable is a problem. So I see I then need const int *method() const as well as int *method(). Once your indexOf() returns a pointer into a member variable thingie you end up needing a const something *indexOf() const and a something *indexOf(Key key), for a method which does the same thing.

                                  Anyways. My head is hurting on this. We may all be saying the same thing in different ways.

                                  Chris KawaC 1 Reply Last reply
                                  0
                                  • JonBJ JonB

                                    @Chris-Kawa

                                    int indexOf(Key key) const { return /* some lengthy way to determine the index */; };
                                    

                                    The problem here is, that function returning int does not exhibit the problem! You don't have to worry about returning int versus const int. It's when function returns a something *. int method() const is never a problem, but int *method() const where it returns a member variable is a problem. So I see I then need const int *method() const as well as int *method(). Once your indexOf() returns a pointer into a member variable thingie you end up needing a const something *indexOf() const and a something *indexOf(Key key), for a method which does the same thing.

                                    Anyways. My head is hurting on this. We may all be saying the same thing in different ways.

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

                                    @JonB said in Return pointer-to-member in const method:

                                    The problem here is, that function returning int does not exhibit the problem!

                                    Exactly, it's intentional on my part and that's the point. Don't try to solve an ugly problem. Redesign and untangle dependencies so there is no problem in the first place ;) int* is an "index" and int* points to data. Untangle those roles.

                                    Anyways. My head is hurting on this.

                                    I fear I might have accidentally terrorized you into being paranoid about something that will bring you marginal gains and make your code a lot worse to read/maintain. I'd say, just for test, do the duplicated const and non-const methods, measure how much gain are you actually getting, decide if it's worth it and only then proceed or revert. While I care deeply about performance there is a line below which it's just not worth it, as in how much optimizations can you achieve in a finite amount of time and how it reflects on readability and ease of maintenance. I'd just like that line to be lower than it usually is, but it's up to you really. Don't let me pressure you too much. I've been told I can be bossy ;)

                                    JonBJ 1 Reply Last reply
                                    2
                                    • Chris KawaC Chris Kawa

                                      @JonB said in Return pointer-to-member in const method:

                                      The problem here is, that function returning int does not exhibit the problem!

                                      Exactly, it's intentional on my part and that's the point. Don't try to solve an ugly problem. Redesign and untangle dependencies so there is no problem in the first place ;) int* is an "index" and int* points to data. Untangle those roles.

                                      Anyways. My head is hurting on this.

                                      I fear I might have accidentally terrorized you into being paranoid about something that will bring you marginal gains and make your code a lot worse to read/maintain. I'd say, just for test, do the duplicated const and non-const methods, measure how much gain are you actually getting, decide if it's worth it and only then proceed or revert. While I care deeply about performance there is a line below which it's just not worth it, as in how much optimizations can you achieve in a finite amount of time and how it reflects on readability and ease of maintenance. I'd just like that line to be lower than it usually is, but it's up to you really. Don't let me pressure you too much. I've been told I can be bossy ;)

                                      JonBJ Offline
                                      JonBJ Offline
                                      JonB
                                      wrote on last edited by JonB
                                      #19

                                      @Chris-Kawa said in Return pointer-to-member in const method:

                                      measure how much gain are you actually getting, decide if it's worth it and only then proceed or revert

                                      Sounds like what I would say :)

                                      While I care deeply about performance

                                      I do, but kinda more just in an algorithmic sense than whether it makes any visible difference to what I'm doing.

                                      Don't let me pressure you too much. I've been told I can be bossy ;)

                                      Not at all! I read your posts with interest, high quality.

                                      This has all revealed something to me which I had not appreciated. I thought Class::method() const only guaranteed that it did not alter *this. I did not expect that, for safety, it also does not allow Class::Member *Class::method() const. That function does not itself alter *this, but I do see that it returns a write-pointer into const this * which could later be used to do so. Hence you have to make that return a const * if you want method() const I just was not aware of this.

                                      I'm sure there are just pages of C++ specs I could/ought to read up on const.... [Actually I think I did so a while ago, I recall it being longggggg.]

                                      P.S.
                                      When I started C it didn't have const yet. Lambs gambolled carefree in the fields, life was easy then...

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

                                        If you want some further discussion points, take a look at how the Qt api returns pointers:

                                        QLayoutItem *QGridLayout::itemAtPosition(int row, int column) const
                                        QUndoStack *QUndoGroup::activeStack() const
                                        QObject *QDropEvent::source() const

                                        want more? :)

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

                                          const is kinda like the GPL license - infectious and intentionally so :)
                                          I won't bring the actual standardese page number, but a close-enough rule for this is on cppreference:

                                          If the operand is an lvalue expression of some object or function type T, operator& creates and returns a prvalue of type T*, with the same cv qualification, that is pointing to the object or function designated by the operand.

                                          What this piece of the typical standardese mumbo jumbo translates to is that when you're doing &member inside a const method it's really &(this->member) and cv-qualifiers (const and volatile) for the resulting pointer are taken from the object this points to. Since you're inside a const method this points to a const object in that scope and so & returns a pointer to const member.

                                          Btw. I've seen an interesting debate somewhere (can't find it now, it was a while ago) about if this should be a const pointer to const object or just a pointer to const object i.e. T const * vs T const * const. The argument for non-const this pointer was some wizardry with modifying this inside a member to avoid vtables. It landed on this being a non-const prvalue and thus non-assignable, but those are some deep trenches :)

                                          @Christian-Ehrlicher said in Return pointer-to-member in const method:

                                          If you want some further discussion points, take a look at how the Qt api returns pointers:

                                          I believe the last two are just straight pointer retrievals so not a big deal. The first one needs that branching logic I mentioned so it's basically against all I've said, but that's a design choice Qt takes. It is well known to take small performance hits here and there for the sake of ease of use and I think it's a fair compromise for all that it offers in return - consistency being a big one. Not a design I would make but hey, can't have it all the way I like :)

                                          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