1. 10
  1.  

  2. 3

    I am following the link to Compiler explorer that the author has provided [1] But I am not seeing any calls to string::_M_create What am I doing wrong? (the compiler that’s auto selected in the explorer is: x86-64 gcc 10.2 with -O1 compile option)

    [1] https://godbolt.org/z/xr1bno

    1. 3

      Try replacing “moo” with “this string is longer than sso”.

      1. 1

        thank you. That helped. Now I am seeing the _M_Create in both scenarios. But there is still a discrepancy (or I am misunderstanding something in the article).

        According to the article, I am supposed to see 1 create in scenario 1 (where std::move) is used, and then 2 _M_Creates in the 2nd scenario.

        However, in the 2nd scenario, I am seeing still just 1 _M_Create call , but there is also a call _M_assign.

        The data transfer instruction (movabs) is present in the M_Create call, but not in _M_assign call. So it seems that the _M_assign call is not creating a copy.

    2. 1

      That temporary is used to construct the parameter value s in the set_s. The argument to the constructor of this s is a temporary – so it’s of type string &&.

      Is it true that all temporaries constructed by the compiler are available as r-value references (or are they just r-values)? Is there a part of the standard in C++11 that guarantees this?

      1. 3

        Yes, temporaries are rvalues by definition, since they don’t have a “name” — they’re not held by or pointed to by a variable. That means a temporary can safely be destroyed (moved out of) as part of the expression, since there’s no way to observe its value afterwards.

        (I am not a licensed C++ guru. But I use rvalues a lot.)

        1. 2

          as r-value references (or are they just r-values)?

          If you have an rvalue, you have an rvalue reference (or at least, you can get one for free). I’m not great with the terminology but I think of the temporary itself as being the rvalue. An rvalue reference can bind to such a temporary. For example, int &&r = 5 + 6; compiles just fine (and does pretty much what you’d expect; as a bonus, the lifetime of the temporary is extended to the scope of the reference, so you don’t immediately get a dangling reference).

          1. 1

            For example, int &&r = 5 + 6; compiles just fine (and does pretty much what you’d expect;

            That’s a really weird line of code. R-value references are usually for function arguments, where temporaries are natural. Honestly, I had no expectations whatsoever what would happen.

            However, it seems to only work for local variables. In this code b is an l-value reference:

            #include <stdio.h>
            
            struct a {
                int&& b;
            
                a(int&& c) : b(c) {}
            };
            
            int main() {
                a a(5+6);
                printf("%d\n", a.b);
            }
            

            And so it doesn’t compile (assigning an r-value to an l-value reference).

            1. 1

              I had no expectations whatsoever what would happen.

              I meant that it assigns r a reference to a temporary object (which is created via the expression 5 + 6), just as it reads.

              However, it seems to only work for local variables. In this code b is an l-value reference:

              No, b is declared as an rvalue reference: int&& b; - just as c.

              However, referring to c (or to b for that matter) still gives an lvalue (otherwise any use would perform a move). You need to explicitly std::move a value to get an rvalue reference:

              #include <algorithm>   // for std::move
              ...
                  a(int&& c) : b(std::move(c)) {}
              

              The same would be true if c was a local variable; there is nothing special about local variables in this regard.

              The difference between something declared an rvalue reference (&&) vs an lvalue reference (&) is what they can bind to. An rvalue reference can bind to an rvalue, an lvalue reference can’t. Each binds only to the corresponding type of value.