Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. Unnecessary const referencing
Qt 6.12 LTS is out! See what's new in the release blog

Unnecessary const referencing

Scheduled Pinned Locked Moved Solved C++ Gurus
18 Posts 7 Posters 5.6k Views 5 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.
  • sierdzioS sierdzio

    @JonB For POD types, passing a copy (int number, int n) is enough. A const reference in such case is needlessly complicating stuff for no gain at all.

    What I often do for POD types, however, is to pass them as const without a reference (const number, const int n). This offers no advantage in terms of performance but makes it kind of clear that these are input parameters and that they will not change.

    J.HilkJ Offline
    J.HilkJ Offline
    J.Hilk
    Moderators
    wrote on last edited by
    #6

    @sierdzio said in Unnecessary const referencing:

    What I often do for POD types, however, is to pass them as const without a reference (const number, const int n). This offers no advantage in terms of performance but makes it kind of clear that these are input parameters and that they will not change.

    I actually like to do that too, but some code models / compilers actually give you a warning about this

    So I usually end up with the declaration of

    void constArgument(int someArgument);
    

    and a definition of

    void SomeClass::constArgument(const int someArgument)
    {
        qDebug() << someArgument;
    }
    

    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


    Q: What's that?
    A: It's blue light.
    Q: What does it do?
    A: It turns blue.

    JonBJ 1 Reply Last reply
    0
    • J.HilkJ J.Hilk

      @sierdzio said in Unnecessary const referencing:

      What I often do for POD types, however, is to pass them as const without a reference (const number, const int n). This offers no advantage in terms of performance but makes it kind of clear that these are input parameters and that they will not change.

      I actually like to do that too, but some code models / compilers actually give you a warning about this

      So I usually end up with the declaration of

      void constArgument(int someArgument);
      

      and a definition of

      void SomeClass::constArgument(const int someArgument)
      {
          qDebug() << someArgument;
      }
      
      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #7

      @J-Hilk
      And why C++ allows you to have a different definition from declaration for this case is beyond me....

      J.HilkJ 1 Reply Last reply
      1
      • JonBJ JonB

        @J-Hilk
        And why C++ allows you to have a different definition from declaration for this case is beyond me....

        J.HilkJ Offline
        J.HilkJ Offline
        J.Hilk
        Moderators
        wrote on last edited by
        #8

        @JonB This is allowed because const is purely an implementation detail when passing by value


        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        1 Reply Last reply
        0
        • JonBJ JonB has marked this topic as solved on
        • JonBJ JonB

          Over in https://forum.qt.io/topic/146160/unresolved-external-symbol-error OP declared:

          template<typename T>
          bool Numbers::isPerfectPower(const T& number, const int &n)
          

          and then proceeds to instantiate it with T as e.g. double.

          On the basis of the C++ mantra of "why write 1 token when you can write 3", is it now the C++ "thing" that we pass numbers as const type & when we could write plain type? I would have written

          template<typename T>
          bool Numbers::isPerfectPower(T number, int n)
          

          For the T unless it's some "complex numeric type", such as perhaps an imaginary or unlimited precision number, why should I prefer const T & over T here? And certainly as for the second argument, why const int & over int?

          Is this just the modern C++ style? Is there some reason why it's more suitable here perhaps in a template? In general do you pass ints as const int &? Or do people just like typing a lot?

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

          There's nothing "technically" wrong here. The problem here is bad API design. On one hand it tries to be generic, so it doesn't restrict the type and uses const& for cases where you pass some "big" type that benefits from passing by reference. On the other it pessimizes the actually intended use case, which are the basic numeric types. So basically it's the worst of both worlds. It's optimized for case it won't be used for.
          A good API design would first analyze use cases. If it's just for the basic types you can restrict the allowed types with something like std::is_arithmetic or a concept and pass by value. If it's for any type, but you don't want to loose on performance for any case then provide an overload for the two ways.

          Christian EhrlicherC 1 Reply Last reply
          3
          • Chris KawaC Chris Kawa

            There's nothing "technically" wrong here. The problem here is bad API design. On one hand it tries to be generic, so it doesn't restrict the type and uses const& for cases where you pass some "big" type that benefits from passing by reference. On the other it pessimizes the actually intended use case, which are the basic numeric types. So basically it's the worst of both worlds. It's optimized for case it won't be used for.
            A good API design would first analyze use cases. If it's just for the basic types you can restrict the allowed types with something like std::is_arithmetic or a concept and pass by value. If it's for any type, but you don't want to loose on performance for any case then provide an overload for the two ways.

            Christian EhrlicherC Offline
            Christian EhrlicherC Offline
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #10

            What's wrong with

            template <typename T>
            bool Numbers::isPerfectPower(T &&number, int n);
            

            :)

            https://godbolt.org/z/afW38b9e8

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

            Chris KawaC 1 Reply Last reply
            1
            • Christian EhrlicherC Christian Ehrlicher

              What's wrong with

              template <typename T>
              bool Numbers::isPerfectPower(T &&number, int n);
              

              :)

              https://godbolt.org/z/afW38b9e8

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

              @Christian-Ehrlicher said:

              What's wrong with

              This:
              https://godbolt.org/z/bxcs7b355

              kshegunovK 1 Reply Last reply
              1
              • JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by
                #12

                God I love this --- an assembly language debate! :D

                J.HilkJ 1 Reply Last reply
                0
                • JonBJ JonB

                  God I love this --- an assembly language debate! :D

                  J.HilkJ Offline
                  J.HilkJ Offline
                  J.Hilk
                  Moderators
                  wrote on last edited by
                  #13

                  @JonB said in Unnecessary const referencing:

                  God I love this --- an assembly language debate! :D

                  alt text


                  Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                  Q: What's that?
                  A: It's blue light.
                  Q: What does it do?
                  A: It turns blue.

                  1 Reply Last reply
                  0
                  • Chris KawaC Chris Kawa

                    @Christian-Ehrlicher said:

                    What's wrong with

                    This:
                    https://godbolt.org/z/bxcs7b355

                    kshegunovK Offline
                    kshegunovK Offline
                    kshegunov
                    Moderators
                    wrote on last edited by
                    #14

                    @Chris-Kawa said in Unnecessary const referencing:

                    @Christian-Ehrlicher said:

                    What's wrong with

                    This:
                    https://godbolt.org/z/bxcs7b355

                    Of course one would do something like this, instead:

                    template <typename T>
                    std::remove_reference_t<T> foo1(T&& a) { return std::forward<T>(a) + 42; }
                    

                    https://godbolt.org/z/8nT5verW4

                    Granted, it still misses the opportunity to use lea instead of resolving the address through mov but works with whatever you pass it. I'd argue that for numeric/primitive types the compiler should expand a const lvalue to a copy at the optimizer pass, but it apparently doesn't.

                    Read and abide by the Qt Code of Conduct

                    JonBJ Chris KawaC 2 Replies Last reply
                    0
                    • kshegunovK kshegunov

                      @Chris-Kawa said in Unnecessary const referencing:

                      @Christian-Ehrlicher said:

                      What's wrong with

                      This:
                      https://godbolt.org/z/bxcs7b355

                      Of course one would do something like this, instead:

                      template <typename T>
                      std::remove_reference_t<T> foo1(T&& a) { return std::forward<T>(a) + 42; }
                      

                      https://godbolt.org/z/8nT5verW4

                      Granted, it still misses the opportunity to use lea instead of resolving the address through mov but works with whatever you pass it. I'd argue that for numeric/primitive types the compiler should expand a const lvalue to a copy at the optimizer pass, but it apparently doesn't.

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

                      @kshegunov
                      Why write this getting-more-complex-all-the-time code if you can instead write:

                      template <typename T>
                      bool Numbers::isPerfectPower(T number, int n);
                      

                      (given usage for POD numerics)? I just don't get how having to know about and add in

                      std::remove_reference_t<T>
                      std::forward<T>
                      

                      is anything other than making C++ harder. I like C++, but what you're asking me, the programmer, to remember is getting out of hand.....

                      Chris KawaC 1 Reply Last reply
                      0
                      • JonBJ JonB

                        @kshegunov
                        Why write this getting-more-complex-all-the-time code if you can instead write:

                        template <typename T>
                        bool Numbers::isPerfectPower(T number, int n);
                        

                        (given usage for POD numerics)? I just don't get how having to know about and add in

                        std::remove_reference_t<T>
                        std::forward<T>
                        

                        is anything other than making C++ harder. I like C++, but what you're asking me, the programmer, to remember is getting out of hand.....

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

                        @JonB said:

                        Why write this getting-more-complex-all-the-time code if you can instead write

                        Because nothing in that syntax prevents you from passing e.g. a BigNum class instance, that would be heavily penalized for using a by value parameter (copy).

                        That's why I mentioned restricting possible inputs e.g.

                        template<typename T>
                        concept ByValueType = std::is_arithmetic_v<T>;
                        
                        template <ByValueType T>
                        bool Numbers::isPerfectPower(T number, int n);
                        

                        or whatever other condition you think is appropriate, like checking the sizeof of the type to see if it fits in a register or using some custom type traits to separate types that should be passed by value from those that benefit from referencing.

                        Of course all of this discussion is academic given how wasteful the actual implementation of the OPs function is. Any benefits we come up on the parameter front are immediately buried just few lines into the function body, but hey, why not :)

                        1 Reply Last reply
                        1
                        • kshegunovK kshegunov

                          @Chris-Kawa said in Unnecessary const referencing:

                          @Christian-Ehrlicher said:

                          What's wrong with

                          This:
                          https://godbolt.org/z/bxcs7b355

                          Of course one would do something like this, instead:

                          template <typename T>
                          std::remove_reference_t<T> foo1(T&& a) { return std::forward<T>(a) + 42; }
                          

                          https://godbolt.org/z/8nT5verW4

                          Granted, it still misses the opportunity to use lea instead of resolving the address through mov but works with whatever you pass it. I'd argue that for numeric/primitive types the compiler should expand a const lvalue to a copy at the optimizer pass, but it apparently doesn't.

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

                          @kshegunov Sure, but that's kinda another topic. What you show is just the intended benefit of small perfectly forwarded functions i.e. they completely disappear via inlining. That wouldn't happen though in a longer function, like what the OP has, so the benefit you show is indeed valid, but not really related to the topic at hand. Notice that you're actually doing what I proposed i.e. have an overload for copy and ref variants. The inlined && forward is just an unrelated complication for style points.

                          Btw. I love how the float version transforms into a fixed point xmm arithmetic with magic constant. Compilers are so smart these days :)

                          kshegunovK 1 Reply Last reply
                          0
                          • Chris KawaC Chris Kawa

                            @kshegunov Sure, but that's kinda another topic. What you show is just the intended benefit of small perfectly forwarded functions i.e. they completely disappear via inlining. That wouldn't happen though in a longer function, like what the OP has, so the benefit you show is indeed valid, but not really related to the topic at hand. Notice that you're actually doing what I proposed i.e. have an overload for copy and ref variants. The inlined && forward is just an unrelated complication for style points.

                            Btw. I love how the float version transforms into a fixed point xmm arithmetic with magic constant. Compilers are so smart these days :)

                            kshegunovK Offline
                            kshegunovK Offline
                            kshegunov
                            Moderators
                            wrote on last edited by kshegunov
                            #18

                            @Chris-Kawa said in Unnecessary const referencing:

                            Notice that you're actually doing what I proposed i.e. have an overload for copy and ref variants.

                            No argument there.

                            The inlined && forward is just an unrelated complication for style points.

                            As far as we are talking + 42, if for example the body was something like:

                            template <typename T>
                            std::remove_reference_t<T> foo1(T&& a) {
                                return smthng(std::forward<T>(a)) + 42;
                            }
                            

                            Where smthng is some other templated nonsense (or simply overloaded), then, I'm sure you'd agree the forward is no longer redundant. :)

                            Btw. I love how the float version transforms into a fixed point xmm arithmetic with magic constant. Compilers are so smart these days :)

                            Yeah, true enough. Although you can still catch them missing optimization opportunities from time to time.

                            @JonB said in Unnecessary const referencing:

                            Why write this getting-more-complex-all-the-time code if you can ...

                            What Chris said (... and since this is indeed an academic discussion at this point).

                            Read and abide by the Qt Code of Conduct

                            1 Reply Last reply
                            0

                            • Login

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