Article Discussion
A Brief Introduction to Rvalue References
Summary: Rvalue references is a small technical extension to the C++ language. Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higher performance and more robust libraries.
63 posts.
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: December 16, 2014 10:40 AM by Roman
    Frank
     
    Posts: 135 / Nickname: fsommers / Registered: January 19, 2002 7:24 AM
    A Brief Introduction to Rvalue References
    March 10, 2008 3:30 PM      
    Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions, and are primarily meant to aid in the design of higher performance and more robust libraries. This article discusses this new feature:

    http://www.artima.com/cppsource/rvalue.html

    What do you think of Rvalue references?
    • Vincent
       
      Posts: 40 / Nickname: vincent / Registered: November 13, 2002 7:25 AM
      Re: A Brief Introduction to Rvalue References
      March 11, 2008 2:58 AM      
      Just for info: It's a C++ article.
      • Nemanja
         
        Posts: 40 / Nickname: ntrif / Registered: June 30, 2004 1:10 AM
        Re: A Brief Introduction to Rvalue References
        March 11, 2008 7:14 AM      
        A very good and informative article. Thanks!
    • David
       
      Posts: 1 / Nickname: davidclark / Registered: September 14, 2007 5:58 AM
      Re: A Brief Introduction to Rvalue References
      March 11, 2008 11:47 AM      
      I am not trying to troll here. Basically the problem is the last thing that C++ needs is even more complications, no matter how good the performance is. I have a more complete explanation on my blog:

      http://prophipsi.blogspot.com/2008/03/why-i-no-longer-like-or-use-c.html
      • Dustin
         
        Posts: 2 / Nickname: ddustin / Registered: March 11, 2008 11:05 AM
        Re: A Brief Introduction to Rvalue References
        March 11, 2008 4:10 PM      
        I've read your blog post. It was most unnecessary.

        Clearly you do not understand the ramifications of this addition so why clutter the internet with that information?
        • dark
           
          Posts: 5 / Nickname: darkmx0z / Registered: March 11, 2008 11:38 AM
          Re: A Brief Introduction to Rvalue References
          March 11, 2008 4:48 PM      
          I second Dustin.

          David, if you dont like the complexity even if it lets you write more efficent code, then you can skip this extra complexity, its not aimed at you.

          C++ was designed to write highly efficent code in a higher, more expressive level than C. In fact, as a replacement for C for most (if not all) tasks. People out there who understand C++ design goals and use it because its the best tool for the job (myself included!) are happy for this extension.
    • Achilleas
       
      Posts: 98 / Nickname: achilleas / Registered: February 3, 2005 2:57 AM
      Re: A Brief Introduction to Rvalue References
      March 12, 2008 5:09 AM      
      I agree with David Clark. C++ is unnecessarily complex, and with rvalue references it's even more stupidly complex.

      First of all, move semantics are silly. C++ is pointer hell, and move semantics make it even more ...hellish. Until now, we had standard rules which allowed us, more or less, to identify where pointers point to (albeit with geometrically progressing difficulty as the code grows). With move semantics, one more complexity order is introduced: we now have to know the internals of the implementation of a class to know how it behaves.

      Take, for example, the example shown in the article, about clone ptrs: it demonstrates all the disadvantages of std::auto_ptr, with no advantage whatsoever. If one erroneously access 'p1' instead of 'p2', 'p1' will be null but inside the scope and show the program will erroneously crash.

      If I wanted to clone an object, I just clone it. A copy constructor should copy the data. Introducing move semantics in a language with manual memory management is a recipe for disaster.

      And the performance gain can be obtained by modifying algorithms. I did not see anything in the article that can't be made with existing C++ with equal performance.

      Finally, the problem of lvalues not allowed to be bound to rvalues is simply a language flaw, which could have been dealt with by constructing a local instance of the rvalue and passing it where an lvalue is required. In the example presented, "5" could be replaced by the compiler by an "int temp = 5;", and then passing temp where an lvalue is required.
    • Nemanja
       
      Posts: 40 / Nickname: ntrif / Registered: June 30, 2004 1:10 AM
      Re: A Brief Introduction to Rvalue References
      March 12, 2008 5:39 AM      
      May I suggest something?

      We all know C++ is complex and there is no need to repeat it in every single C++ related discussion that takes place around.

      How about writing an article named "C++ is too complex"?People could pour all their frustrations in one place and give us a break.

      Or maybe each C++ article should have a disclaimer in red: "Yes, we already know C++ is complex, so please disregard this fact when discussing the article".

      Sorry for the sarcasm, but this is becoming frustrating.
      • Roland
         
        Posts: 25 / Nickname: rp123 / Registered: January 7, 2006 9:42 PM
        Re: A Brief Introduction to Rvalue References
        March 12, 2008 2:01 PM      
        People who complain about nuisances at least care a little about a thing. Those who don't have abandoned it. BTW, the desired article has been written, see esp. question 3 http://www.bookpool.com/ct/98031 .
        • dark
           
          Posts: 5 / Nickname: darkmx0z / Registered: March 11, 2008 11:38 AM
          Re: A Brief Introduction to Rvalue References
          March 12, 2008 2:31 PM      
          yet he says:

          0. Do you see C++ ever getting simpler? Dropping features, prohibiting co-use of certain features, etc.?
          I don't think there is any practical way that C++ can get meaningfully simpler. Any change to the rules of C++ that is not backwards-compatible will face tremendous resistance in the standardization committee, and I think this is proper: it's bad policy to make changes that break programs that are currently legal, and it's even worse for the semantics of legal programs to be modified, i.e., for "silent" changes to be foisted on developers.


          Of course C++ could be simpler. If he had all the amount of knowledge we have now back in 1970, Im pretty sure C++ would be way smaller and way simpler it currently is. We could say the same thing about other languages (Java for example, they deprecate huge parts of its standard library without any shame because they add something in the language that outdates the old design). Unless someone comes with a better language (probably a cleaned-up C++ following the same design goals and just taking away some obsolete things from here and there, Java was a failure in that way considering Gosling wanted it to be a C++ replacement but in the end it just came to fill another (actually big) niche) I will still use C++.
    • Matthew
       
      Posts: 1 / Nickname: matman / Registered: July 26, 2005 11:33 AM
      Re: A Brief Introduction to Rvalue References
      March 12, 2008 9:20 PM      
      In short: Best. Language feature. Ever. I love rvalue references and move semantics. Cleanly passing ownership of some data from one place to another makes me smile.
    • Nemanja
       
      Posts: 40 / Nickname: ntrif / Registered: June 30, 2004 1:10 AM
      Re: A Brief Introduction to Rvalue References
      March 13, 2008 6:43 AM      
      Another text on the same topic: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=310
    • Steve
       
      Posts: 2 / Nickname: sbmassey / Registered: May 23, 2006 3:21 PM
      Re: A Brief Introduction to Rvalue References
      March 14, 2008 4:26 AM      
      Most new languages over the last couple of decades seem to aspire to be either Smalltalk or Haskell. C++ is the only language whose design is intended to give the developer more control over low level aspects of the machine, while still supporting modern software techniques. It is probably too complex for a lot of uses, but then no other language can distinguish between copying and moving at the language level, as described in the article. Sure, in a Smalltalk-ish language you would implement swap() by switching the references to objects around, but that has the cost of requiring an additional layer of indirection for you to perform the swap. If you need low level efficiency, C++ is a good bet.
    • White
       
      Posts: 4 / Nickname: wwolf / Registered: July 24, 2004 9:33 AM
      Re: A Brief Introduction to Rvalue References
      March 14, 2008 8:51 AM      
      Sorry for being off-topic... I don't want to talk about the complexity of C++, but about the actual article.

      I wonder how the heck can an article end up on Artima, signed by Bjarne and have a serious programming error in it???

      I talk about the exception safety of the clone_ptr assignment operator. Honestly, who write this article? What do the 10+ people on the editorial board do, if this gets published? Sorry for being upset a bit, but it may take literally *years* to "unteach" people who learn from material signed by Bjarne...

      So PLEASE, change this:

      clone_ptr& operator=(const clone_ptr& p)
      {
      if (this != &p)
      {
      delete ptr;
      ptr = p.ptr ? p.ptr->clone() : 0;
      }
      return *this;
      }

      to something like this:

      clone_ptr& operator=(const clone_ptr& p) {
      if (this == &p) return *this;
      T *ptrt== p.ptr ? p.ptr->clone() : 0;
      delete ptr;
      ptr=ptrt;
      return *this;
      }

      or any of the possible many variations that won't leave clone_ptr::ptr point to 0xDEADBEEF if p.ptr->clone() throws...

      Attila aka ww
    • Dustin
       
      Posts: 2 / Nickname: ddustin / Registered: March 11, 2008 11:05 AM
      Re: A Brief Introduction to Rvalue References
      March 11, 2008 4:08 PM      
      This is a great addition. I've always felt the previous solution for these sorts of issues was rather awkward (reverting to pointers) and it had the obvious performance side effects.

      This will ofcourse be a hard time for gcc, as the double ampersand is used for goto pointers. A lot of code is likely to break.
      • Howard
         
        Posts: 9 / Nickname: hinnant / Registered: December 16, 2007 7:49 AM
        Re: A Brief Introduction to Rvalue References
        March 14, 2008 3:35 PM      
        Now you can try it out in gcc 4.3.
        • White
           
          Posts: 4 / Nickname: wwolf / Registered: July 24, 2004 9:33 AM
          Re: A Brief Introduction to Rvalue References
          March 15, 2008 10:36 AM      
          Wow. I should.
    • Achilleas
       
      Posts: 98 / Nickname: achilleas / Registered: February 3, 2005 2:57 AM
      Re: A Brief Introduction to Rvalue References
      March 17, 2008 9:30 AM      
      Since the creators of the language visit this board, could they please drop a few comments on the viability/usability of the move semantics on the programming language perspective level? methinks it's a bad move, because of all the problems of move semantics as we know them from std::auto_ptr...
      • Howard
         
        Posts: 9 / Nickname: hinnant / Registered: December 16, 2007 7:49 AM
        Re: A Brief Introduction to Rvalue References
        March 17, 2008 11:27 AM      
        > Since the creators of the language visit this board, could
        > they please drop a few comments on the viability/usability
        > of the move semantics on the programming language
        > perspective level? methinks it's a bad move, because of
        > all the problems of move semantics as we know them from
        > std::auto_ptr...

        I consider std::auto_ptr a pioneer in the area of move semantics. There is one very important detail it got wrong (and had little choice given the lack of language support in C++98): It moves from lvalues.

        The move semantics framework in C++0X will not implicitly move from lvalues (with a couple of exceptions noted below). It will only move from rvalues. When you move from an rvalue, no other part of your program will notice because if you know you have a reference to an rvalue, then you also know that no other part of your program is referencing that rvalue.

        Exception 1:

        Sometimes it is advantageous for the programmer to be able to say: "treat this lvalue as an rvalue for this one operation". The programmer might want to do this when he knows (for example) that right after he "copies" from x, he is going to assign a new value to it, or destruct it anyway. So the old value of x is no longer valuable to the program logic (except as "copied" to the new location). A prime example is when vector reallocates its buffer. There is no need to copy values from the old buffer to the new; they can often be much more efficiently moved from the old buffer to the new buffer. To do so, the author of vector must explicitly specify the operation as a move since the values in the old buffer are lvalues.

        Exception 2:

        When copy elision is legal, but unable to be performed, an implicit move from an lvalue can be performed. Example:


        A foo(bool b)
        {
        A a1, a2;
        if (b)
        return a2;
        return a1;
        }


        In the above example, it is legal but exceedingly difficult for the compiler to perform Return Value Optimization. In C++0X the compiler will treat a1 and a2 as rvalues in the return statements. If A has a move constructor, it will be used. Else if A has a copy constructor it will be used. Else the program is ill-formed.

        The result of these rules is that some programs which make heavy use of STL or other move-enabled libraries may simply start to execute much faster by simply recompiling in C++0X: with no changes needed, with no rvalue reference or move in sight, and no change in semantics. However in the interest of backwards compatibility, for the user's own classes to start moving, he will have to explicitly code move constructors and move assignment. When he does so, the framework is designed so that his clients will simply experience increased performance, and not a change in semantics.

        Further background information regarding move semantics and auto_ptr can be found here:

        http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1856.html#20.4.5%20-%20Class%20template%20auto_ptr

        The most important points of this link are:

        1. One should not move from lvalues using copy syntax. Other syntax for moving should be used instead. Otherwise generic code is likely to initiate a move when a copy was intended.

        2. Even though it is unsafe to move from an lvalue with copy syntax, it is both safe and desirable to move from an rvalue with copy syntax. When an rvalue binds to a function, that function has a unique reference to the rvalue and thus can safely modify it.
        • Achilleas
           
          Posts: 98 / Nickname: achilleas / Registered: February 3, 2005 2:57 AM
          Re: A Brief Introduction to Rvalue References
          March 19, 2008 5:10 AM      
          > I consider std::auto_ptr a pioneer in the area of move
          > semantics. There is one very important detail it got
          > wrong (and had little choice given the lack of language
          > support in C++98): It moves from lvalues.

          I don't think the problem was the lack of rvalues. Every time I tried to use std::auto_ptr, I had problems. And even if the initial code was correct, after changing the code many problems with invalid ownerships and deletions of objects in the wrong places came up.
        • Achilleas
           
          Posts: 98 / Nickname: achilleas / Registered: February 3, 2005 2:57 AM
          Re: A Brief Introduction to Rvalue References
          March 19, 2008 5:28 AM      
          > Exception 2:
          >
          > When copy elision is legal, but unable to be performed, an
          > implicit move from an lvalue can be performed. Example:
          >
          >
          > A foo(bool b)
          > {
          > A a1, a2;
          > if (b)
          > return a2;
          > return a1;
          > }
          >

          >
          > In the above example, it is legal but exceedingly
          > difficult for the compiler to perform Return Value
          > Optimization.

          I don't understand why the compiler can't perform return value optimization. In an optimizing build, the compiler could eliminate the two created instances and construct the result directly, whatever path is taken.

          >
          > The result of these rules is that some programs which make
          > heavy use of STL or other move-enabled libraries may
          > simply start to execute much faster by simply recompiling
          > in C++0X: with no changes needed, with no rvalue
          > reference or move in sight, and no change in semantics.
          > However in the interest of backwards compatibility, for
          > r the user's own classes to start moving, he will have to
          > explicitly code move constructors and move assignment.
          > When he does so, the framework is designed so that his
          > s clients will simply experience increased performance,
          > and not a change in semantics.

          I have to disagree. Move semantics is a very big change. Consider the following example:


          void bar() {
          A a = foo();
          A b = a; //move
          a->doSomething(); //oops, a's contents are null.
          }


          > 1. One should not move from lvalues using copy syntax.
          > Other syntax for moving should be used instead. Otherwise
          > generic code is likely to initiate a move when a copy was
          > intended.

          Which means I would have to use the function 'move' every time I want to move data, instead of copying them.

          This could be achieved easily by a move object; the compiler certainly did not need rvalues. You could do it like this:


          template <class T> class move_t {
          ///bla bla
          };

          //move function returns a move object from the given reference
          template <class T> move_t<T> move(T &p) {
          return move_t<T>(p);
          }

          //use move
          A b = move(a);


          But I see a contradiction here: you say that "there is no need to modify code and the move constructor will be implicitely used to increase performance", and now you say that "the move function should be used, for safety reasons". Not very good, in my opinion.

          > 2. Even though it is unsafe to move from an lvalue with
          > copy syntax, it is both safe and desirable to move from an
          > rvalue with copy syntax. When an rvalue binds to a
          > function, that function has a unique reference to the
          > rvalue and thus can safely modify it.

          So in complex expressions of the form:


          foo(b, bar(a, a.foo(b.bar(a)), a)


          it's going to be a hell of a lot difficult to understand why the program crashes! move semantics makes destruction almost random.
    • Mathias
       
      Posts: 1 / Nickname: loufoque / Registered: May 15, 2008 1:35 AM
      Re: A Brief Introduction to Rvalue References
      May 15, 2008 6:48 AM      
      It seems there are a few errors(?) in that article.

      First, this piece of code:
          clone_ptr& operator=(const clone_ptr& p)
      {
      if (this != &p)
      {
      delete ptr;
      ptr = p.ptr ? p.ptr->clone() : 0;
      }
      return *this;
      }


      If p.ptr->clone() throws, ptr is left in a dangerous state, which will likely produce a segfault when the destructor is called.
      Two solutions:
      - clone before deleting (better, since you keep the old value)
      - catch the exception and set ptr to 0 (objects ends up empty)

      Second, this piece of code:
          clone_ptr& operator=(clone_ptr&& p)
      {
      std::swap(ptr, p.ptr);
      return *this;
      }

      Transfering the old pointed-to value to the rvalue (which might actually not really be one) doesn't seem like a good idea, since you can't really tell when it's gonna be freed.
      It seems more reasonable to do
      delete ptr;
      ptr = p.ptr
    • Jan
       
      Posts: 4 / Nickname: janbessai / Registered: September 24, 2008 3:10 AM
      Re: A Brief Introduction to Rvalue References
      September 24, 2008 9:22 AM      
      To distract from the controversial point of GC and to get back to topic:

      If there is something I miss in C++, it is a simple way to write getters without unnecessary performance overhead.

      The current state in code:

      Method 1:

      class Foo {
      private:
      Bar member;
      public:
      ...
      Bar get_modified_member() const {
      Bar result = member;
      result.modify();
      return result;
      }
      };

      This has the overhead of copying the result variable (RVO is not to be considered here, as it is no language feature and too compiler dependent to really rely on).

      Method 2:

      class Foo {
      ...
      Bar & get_modified_member(Bar & result) const {
      result = member;
      result.modify();
      return result;
      }
      };

      void some_calling_function {
      Foo foo;
      ...
      Bar bar;
      foo.get_modified_member(bar);
      }

      This is rather ugly to read (+needs extra documentation) and has the overhead of creating a local instance of Bar, which can be dangerous or even impossible if Bar has a side effected default constructor or if Bar is a template typename and is unknown to have a default constructor at all.

      Method 3:

      class Foo {
      ...
      Bar * get_modified_member() const {
      Bar * result = 0;
      result = new Bar(member);
      return result;
      }
      };

      This is rather efficient, but needs extra considerations based on type details of Bar, if Bar has no copy constructor. Furthermore it brings in all problems of heap(/store) allocated memory management. This method could be improved with smart pointers, but that still needs extra work to avoid cyclic referencing and whatever other pitfalls the chosen smartpointer implementation has. The amount of extra documentation needed is in each case tremendous.


      Do I get it correctly now, that C++0x will add
      Method 4:

      class Foo {
      ...
      Bar get_modified_member() const {
      result = member;
      result.modify();
      return std::move(result);
      }
      };

      This will be efficient. It requires Bar to have a movement constructor.

      If so (to be meant asking, not criticizing):
      1. What will be returned if std::move(result) throws for some reason?
      2. Is there any way to make sure or at least check, that Bar has a movement constructor (maybe using concepts?)? If so, how would that way look? Would it add difficult extra code?
      3. Have you considered how to explain the std::move command and rvalue references to novices in an easy way? C++ is complex, but there must be somewhere to start and I think simple standard getter methods should remain a fully understandable part for beginners.

      Besides I'd like to add two different ways of approaching the result value problem, which might be a consideration, too:
      Method 5 (inspired by Delphi):

      class Foo {
      ...
      Bar get_modified_member() const {
      result = member;
      result.modify();
      }
      };

      This method implies that each function gets an implicitly existing value to store the function results in. It is quite similar to early NRVO approaches. For flexibility and naming reasons it could by done by a new language keyword, too:
      Method 5 (modified):

      class Foo {
      ...
      Bar get_modified_member() const {
      resulting Bar result = member;
      result.modify();
      return result;
      }
      };

      The resulting keyword could have the compiler explicitly turn on RVO for one local variable per function and thereby make RVO a reliable language feature.

      Last (and least) an ugly workaround approach inspired by the way Java can instantiate arrays of generic types without knowing if a default constructor exists (java.lang.reflect.Array.newInstance(...))
      Method 6:

      class Foo {
      ...
      Bar & get_modified_member(Bar & result) const {
      result(member);
      result.modify();
      return result;
      }
      };

      void some_calling_function {
      Foo foo;
      ...
      Bar bar = std::uninitialized_object<Bar>();
      foo.get_modified_member(bar);
      }


      Method 5 (modified) would be my favorite addition to C++, as it is simple to use, compilers with RVO don't need many changes to implement it and it is most easy to explain.

      Thanks for reading and maybe for answering :)!
      • rgamarra79
         
        Posts: 7 / Nickname: rgamarra79 / Registered: September 26, 2008 3:00 AM
        Re: A Brief Introduction to Rvalue References
        September 26, 2008 9:35 AM      
        Hi all,

        I was trying to get familiarity with the concept of Rvalue references. While reading this article, the definition of forward has something I can't understand: the need for identity<T>::type:


        template <class T>
        T&& forward(typename identity<T>::type&& a)
        {
        return a;
        }


        Why can't it be done simply as the following?


        template <class T>
        T&& forward(T&& a)
        {
        return a;
        }


        I'm sure I'm missing something, but I can't figure it out.

        In http://www.pdc.kth.se/training/Talks/C++/boost/libs/mpl/doc/index.html it can be read


        // on the face of it, not very useful
        template< typename T >
        struct identity
        {
        typedef T type;
        }


        I also took a look at http://www.boost.org/doc/libs/1_36_0/libs/mpl/doc/refmanual/identity.html.

        On the other hand


        template <class T>
        typename remove_reference<T>::type&&
        move(T&& a)
        {
        return a;
        }


        does the its thing the other way round: using some MPL techniques for the return value and not for the argument's type.

        Thanks a lot in advance.

        Rodolfo.
        • Jan
           
          Posts: 4 / Nickname: janbessai / Registered: September 24, 2008 3:10 AM
          Re: A Brief Introduction to Rvalue References
          September 26, 2008 2:55 PM      
          C++0x should support template typedefs anyway. So you should be perfectly right as far as I can see it.
          • rgamarra79
             
            Posts: 7 / Nickname: rgamarra79 / Registered: September 26, 2008 3:00 AM
            Re: A Brief Introduction to Rvalue References
            September 27, 2008 3:41 PM      
            Thanks Jan.

            I wasn't thinking about template typedefs, but it's good to have them in consideration. Indeed the technique used (identity struct) is the usual workaround to the lack of them (http://www.gotw.ca/gotw/079.htm).

            I just could not see the need for that identity template struct, as its inner "typedef T type" would be equivalent to T.

            So I asked myself: Why not just use T&& in forward's arg list (just like in the case of move)? And could not find a good reason.

            I actually tried some examples (with regular references) and the the function could be defined (overloaded) both ways simultaneously. It seems that using identity makes it harder for the compiler to resolve the proper function: may identity be used to enforce typename specialization when calling the template function?

            Below the code I tried. Thanks. Rodolfo.


            #include<iostream>
            // Identity struct.
            template<typename T>
            struct identity {
            typedef T type;
            };
            //--
            // Overloaded funcs.
            // Both ways
            template<typename T>
            int foo1(T& t){
            return 0;
            }
            template <typename T>
            int foo1(typename identity<T>::type& t){
            return 1;
            }
            // Only directly
            template<typename T>
            int foo2(T& t){
            return 2;
            }
            // Only with identity.
            template<typename T>
            int foo3(typename identity<T>::type& t){
            return 3;
            }
            // Main.
            int main(){
            int a = 0;
            std::cout << foo1(a) << std::endl;
            // error: call of overloaded ‘foo1(int&)’ is ambiguous
            // std::cout << foo1<int>(a) << std::endl;
            std::cout << foo2(a) << std::endl;
            std::cout << foo2<int>(a) << std::endl;
            // error: no matching function for call to ‘foo3(int&)’
            // std::cout << foo3(a) << std::endl;
            std::cout << foo3<int>(a) << std::endl;
            return 0;
            }
            • Jan
               
              Posts: 4 / Nickname: janbessai / Registered: September 24, 2008 3:10 AM
              Re: A Brief Introduction to Rvalue References
              October 1, 2008 11:22 AM      
              Hi Rodolfo,
              I think foo3(a) does not work for a reason. Consider this:

              include <iostream>

              template<typename T>
              struct identity {
              typedef T type;
              };

              template <typename T>
              struct identity_rek {
              typedef typename T::type type;
              };

              template<typename T>
              int foo3(typename identity<T>::type& t){
              return 3;
              }

              template <typename T>
              int foo4(typename identity_rek<T>::type& t) {
              return 4;
              }


              int main(){
              int a = 0;
              // "simple" case
              std::cout << foo3<identity_rek<identity<int> >::type>(a) << std::endl;
              // "evil" case
              std::cout << foo3<identity_rek<identity_rek<identity_rek<identity<int> > > >::type>(a) << std::endl;
              // compiler riddle
              std::cout << foo3(a) << std::endl;
              // "more evil" case
              std::cout << foo4<identity<identity_rek<identity<int> > >::type>(a) << std::endl;
              // "more evil" riddle
              std::cout << foo4(a) << std::endl;
              return 0;
              }


              The compiler riddles have an infinite amount of solutions (making the result indeterministic) and could be constructed even worse. I guess algorithms to solve them would have to be heuristic. Maybe some solutions can even end up in an infinite recursion.
              To have the compiler find out a right type to fill the template with (only by knowing that a is int) therefore is almost impossible.
              Greetings and sorry for the brain damaging example,
              Jan

              PS.: Consider that all types "a" can be casted to would be valid solutions, too - adding infinite possible fillins and ambiguities again.
    • Niels
       
      Posts: 9 / Nickname: dekker / Registered: September 7, 2006 6:14 AM
      Re: A Brief Introduction to Rvalue References
      March 13, 2008 1:59 PM      
      I find those rvalue references very interesting. I'm working in the field of medical image processing (www.lkeb.nl), and performance is very much an issue for us. So I expect rvalue references to be very helpful...

      Now I wonder, should the next version of the standard library still provide overloads of std::swap for all of the STL containers? It looks like the most generic version, template <class T> swap(T& a, T& b), should be good enough by then!
      • Howard
         
        Posts: 9 / Nickname: hinnant / Registered: December 16, 2007 7:49 AM
        Re: A Brief Introduction to Rvalue References
        March 14, 2008 3:47 PM      
        > Now I wonder, should the next version of the standard
        > library still provide overloads of std::swap
        > for all of the STL containers? It looks like the most
        > generic version, template <class T> swap(T&
        > a, T& b)
        , should be good enough by then!

        Thanks for your kind comment Niels. To answer your question above, No. Explanation:

        You are right that the generic swap is *much* more efficient now, using move construction and move assignment. However the generic swap is still 2-3 times as expensive as the overloaded swap for vector (for example). For quick coding/prototyping and for non-performance critical code, the generic swap can be much faster now (if the class provides move constructor and assignment). But std::containers such as vector are used *so* much that attention to detail is paramount. Thus even "twice as fast as blazingly fast" is worth a few extra lines of code.

        Details: vector move construction, move assignment and swap are all approximately the same cost. The generic swap will do one move construction and two move assignments.
        • Niels
           
          Posts: 9 / Nickname: dekker / Registered: September 7, 2006 6:14 AM
          Re: A Brief Introduction to Rvalue References
          March 16, 2008 2:40 PM      
          Thanks for your reply, Howard.

          > You are right that the generic swap is *much* more efficient now,
          > using move construction and move assignment. However the generic
          > swap is still 2-3 times as expensive as the overloaded swap for
          > vector (for example).

          Well... I doubt if an overloaded version for a specific container would be significantly faster than that clever generic swap you've presented, when doing all kinds of compiler optimizations. But when running a non-optimized "debug" version of a program, I guess you're right about the overloaded version being 2-3 times faster. Which sounds worthwhile to me.

          Still there are quite a few more overloaded swap functions added to the draft of the next C++ Standard (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2521.pdf), having an rvalue reference as one of its arguments. Isn't a swap with an rvalue reference equivalent to a move assignment? Are the following two lines of code equivalent (assuming that GetSomeVector() returns a vector by value)?


          swap(vec, GetSomeVector() ); // swap with an rvalue ref.
          vec = GetSomeVector(); // Do a move assignment!
          • Howard
             
            Posts: 9 / Nickname: hinnant / Registered: December 16, 2007 7:49 AM
            Re: A Brief Introduction to Rvalue References
            March 16, 2008 4:02 PM      
            > Still there are quite a few more overloaded swap functions
            > added to the draft of the next C++ Standard
            > (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2
            > 521.pdf), having an rvalue reference as one of its
            > arguments. Isn't a swap with an rvalue reference
            > equivalent to a move assignment? Are the following
            > two lines of code equivalent (assuming that
            > GetSomeVector() returns a vector by value)?
            >
            >
            > swap(vec, GetSomeVector() ); // swap with an rvalue
            > ue ref.
            > vec = GetSomeVector(); // Do a move assignment!
            >


            You've hit upon an interesting grey area where the current working draft disagrees with the intent of the rvalue ref proposal. This disagreement is mainly one of getting the wording right, as opposed to a disagreement on the intent.

            Assuming the desired intent, these two lines of code are nearly equivalent.

            The first swaps the two vectors, and then destroys the data originally held in vec.

            The second destroys the data originally held in vec and then swaps the two vectors.

            The difference might be important when the vector holds items whose destructors have side effects whose timing might be significant (e.g. vector<thread>). LWG 675 (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#675) is currently tracking this issue.
            • Niels
               
              Posts: 9 / Nickname: dekker / Registered: September 7, 2006 6:14 AM
              Re: A Brief Introduction to Rvalue References
              March 17, 2008 5:29 AM      
              >> Are the following two lines of code equivalent?

              swap(vec, GetSomeVector() ); // swap with an rvalue ref.
              vec = GetSomeVector(); // Do a move assignment!

              Howard Hinnant replied:
              > The first swaps the two vectors, and then destroys the data originally held in vec.
              > The second destroys the data originally held in vec and then swaps the two vectors.
              > The difference might be important when the vector holds items whose destructors
              > have side effects whose timing might be significant (e.g. vector<thread>).
              > LWG 675 (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#675) is
              > currently tracking this issue.

              Thanks, Howard! So in a worst case scenario, the move assignment of a vector might have O(n) complexity (according to LWG 675), while a vector swap would still have O(1) complexity, right?

              Is there also any difference between doing std::swap, having an rvalue reference as argument, and calling the swap member function on a temporary? Or are the following two lines of code equivalent?

              swap(vec, GetSomeVector() );
              GetSomeVector().swap(vec);
              • Howard
                 
                Posts: 9 / Nickname: hinnant / Registered: December 16, 2007 7:49 AM
                Re: A Brief Introduction to Rvalue References
                March 17, 2008 7:33 AM      
                > So in a worst case scenario, the move
                > assignment of a vector might have O(n) complexity
                > (according to LWG 675), while a vector swap would still
                > have O(1) complexity, right?

                Right, assuming equal allocators in all cases (unequal allocators bring in other issues which are still in flux.

                Note if you're swapping with a temporary, then the destruction of that temporary may be O(n). But that cost isn't attributed to the swap itself.

                > Is there also any difference between doing std::swap,
                > having an rvalue reference as argument, and calling the
                > swap member function on a temporary? Or are the following
                > two lines of code equivalent?
                >
                > swap(vec, GetSomeVector() );
                > GetSomeVector().swap(vec);
                >


                These should be equivalent. And this too:


                vec.swap(GetSomeVector());
                • Niels
                   
                  Posts: 9 / Nickname: dekker / Registered: September 7, 2006 6:14 AM
                  Re: A Brief Introduction to Rvalue References
                  March 17, 2008 8:15 AM      
                  >> [...] are the following two lines of code equivalent?
                  >>
                  >> swap(vec, GetSomeVector() );
                  >> GetSomeVector().swap(vec);

                  Howard Hinnant replied:
                  > These should be equivalent. [...]

                  Thanks! Interestingly, the current working draft (N2521.pdf) doesn't have generic std::swap overloads, to support passing an rvalue reference argument. I guess they could have been added, as follows:

                  template<class T> void swap(T&& a, T& b);
                  template<class T> void swap(T& a, T&& b);

                  Are those overloads left out intentionally?
                  • Howard
                     
                    Posts: 9 / Nickname: hinnant / Registered: December 16, 2007 7:49 AM
                    Re: A Brief Introduction to Rvalue References
                    March 17, 2008 8:49 AM      
                    > Thanks! Interestingly, the current working draft
                    > (N2521.pdf) doesn't have generic std::swap
                    > overloads, to support passing an rvalue reference
                    > argument. I guess they could have been added, as follows:
                    >
                    > template<class T> void swap(T&& a, T& b);
                    > template<class T> void swap(T& a, T&& b);
                    >

                    > Are those overloads left out intentionally?

                    Yes, they were intentionally left out. I was nervous about allowing statements such as:


                    int i = 0;
                    std::swap(i, 2);


                    The motivation for allowing containers to swap with rvalues grew out of the desire to generalize the vector "swap trick":


                    vector<int> v(...);
                    vector<int>(v).swap(v); // C++03
                    v.swap(vector<int>(v)); // C++0X
                    swap(v, vector<int>(v)); // C++0X


                    I.e. just trying to make the swap trick a little easier to read and write.

                    Currently the draft generally contains 3 namespace scope swap signatures for library components (in general):


                    // pseudo code
                    swap(vector&, vector&);
                    swap(vector&&, vector&);
                    swap(vector&, vector&&);


                    The motivation for the three signatures is to prohibit clients from accidently swapping two rvalue vectors which is almost definitely a mistake. However there is currently some (quite understandable) feeling on the committee that this is overkill and we might want to replace the above three signatures with just this one:


                    // pseudo code
                    swap(vector&&, vector&&);


                    which would allow either argument to be lvalue or rvalue (in all 4 combinations). Neither solution has a performance or code size advantage over the other, and the safety enhancement of the 3-signature pack is quite minimal. So it is a close call in deciding the proper way to go, and I am comfortable with either choice.
                    • Niels
                       
                      Posts: 9 / Nickname: dekker / Registered: September 7, 2006 6:14 AM
                      Re: A Brief Introduction to Rvalue References
                      March 17, 2008 9:25 AM      
                      Howard wrote:
                      > I was nervous about allowing statements such as:
                      > int i = 0;
                      > std::swap(i, 2);

                      Wouldn't it just make a temporary, having the value 2, and swap i and the temporary?

                      > The motivation for allowing containers to swap with
                      > rvalues grew out of the desire to generalize the vector
                      > "swap trick"

                      Okay, like you wrote at:
                      http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1858.html#23.2%20-%20Sequences

                      Personally I would prefer to have a dedicated shrink_to_fit function for this purpose. As proposed by Beman Dawes, LWG issue 755, std::vector and std:string lack explicit shrink-to-fit
                      operations
                      http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#755

                      But anyway, the new std::array container doesn't have std::swap overloads for rvalue references either. Are those left out because an array cannot shrink?
                      • Howard
                         
                        Posts: 9 / Nickname: hinnant / Registered: December 16, 2007 7:49 AM
                        Re: A Brief Introduction to Rvalue References
                        March 17, 2008 10:56 AM      
                        > Howard wrote:
                        > > I was nervous about allowing statements such as:
                        > > int i = 0;
                        > > std::swap(i, 2);
                        >
                        > Wouldn't it just make a temporary, having the value 2, and
                        > swap i and the temporary?

                        Probably. I've never had the motivation to find out. I.e. I don't find swap(i, 2) a motivating use case.

                        > > The motivation for allowing containers to swap with
                        > > rvalues grew out of the desire to generalize the vector
                        > > "swap trick"
                        >
                        > Okay, like you wrote at:
                        > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n18
                        > 58.html#23.2%20-%20Sequences
                        >
                        > Personally I would prefer to have a dedicated
                        > shrink_to_fit function for this purpose. As proposed by
                        > Beman Dawes, LWG issue 755, std::vector and std:string
                        > lack explicit shrink-to-fit
                        > operations

                        > http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html
                        > #755

                        This looks likely to pass as well.

                        > But anyway, the new std::array container doesn't have
                        > std::swap overloads for rvalue references either. Are
                        > those left out because an array cannot shrink?

                        I suspect this is simply an oversight. We're still working feverishly on the draft.
                        • Niels
                           
                          Posts: 9 / Nickname: dekker / Registered: September 7, 2006 6:14 AM
                          Re: A Brief Introduction to Rvalue References
                          March 17, 2008 0:23 PM      
                          Howard wrote:
                          > I don't find swap(i, 2) a motivating use case.

                          In templated code, you might want to do something like swap(foo, CreateNewFoo()), for foo being either an STL container or a built-in type... Would that be a motivating use case to you?

                          >> Personally I would prefer to have a dedicated
                          >> shrink_to_fit function for this purpose. As
                          >> proposed by Beman Dawes, LWG issue 755 [...]
                          > This looks likely to pass as well.

                          I'm glad to hear so! I hope that the new Standard will specify that shrink_to_fit should be at least as effective as the swap trick...

                          >> But anyway, the new std::array container doesn't have
                          >> std::swap overloads for rvalue references either.
                          >
                          > I suspect this is simply an oversight.

                          So even without being shrinkable, you still think that std::array should have the same kinds of swap overloads as the other STL containers, right? It sounds like those overloads would become part of the STL container "concept"...
                          • Howard
                             
                            Posts: 9 / Nickname: hinnant / Registered: December 16, 2007 7:49 AM
                            Re: A Brief Introduction to Rvalue References
                            March 17, 2008 4:26 PM      
                            > Howard wrote:
                            > > I don't find swap(i, 2) a motivating use case.
                            >
                            > In templated code, you might want to do something
                            > like swap(foo, CreateNewFoo()), for
                            > foo being either an STL container or a
                            > built-in type... Would that be a motivating use case to
                            > you?

                            <shrug> Maybe. I've seen the motivation with wanting to swap with an rvalue container. But over the past decade I haven't run across someone complaining that the general swap doesn't accept rvalues, with the exception of use of proxy references. And in this latter case the solution seems to be to overload swap on your proxy reference.

                            I guess I'm a "squeaky wheel" kind of guy. I know I can't solve all the problems. So I try to tackle what I perceive to be the biggest problems first. How serious is this problem you're point out? You just would not believe the effort it takes to get a change through committee... (which is as it should be)

                            > >> But anyway, the new std::array container doesn't have
                            > >> std::swap overloads for rvalue references either.
                            > >
                            > > I suspect this is simply an oversight.
                            >
                            > So even without being shrinkable, you still think that
                            > std::array should have the same kinds of swap overloads as
                            > the other STL containers, right? It sounds like those
                            > overloads would become part of the STL container
                            > "concept"...

                            It's swap capability should probably be consistent with the other containers (whatever we decide that capability is). It would be awkward if one could swap against an rvalue vector but not an rvalue array. But I see a much larger difference when I sub in "rvalue scalar" into that consistency argument. C++ is very much a pragmatic language, as opposed to a pure theory language.
                            • Niels
                               
                              Posts: 9 / Nickname: dekker / Registered: September 7, 2006 6:14 AM
                              Re: A Brief Introduction to Rvalue References
                              March 18, 2008 11:44 AM      
                              >> In templated code, you might want to do something
                              >> like swap(foo, CreateNewFoo()), for foo
                              >> being either an STL container or a built-in type... Would that be
                              >> a motivating use case to you?
                              >
                              > <shrug> Maybe.

                              Okay... now suppose there's a third party class, ThirdPartySpace::Foo, having an accessible move constructor and move assignment operator. Unfortunately the third party didn't provide an overload to swap an rvalue of this class. Still the user might want to do so, within her own namespace:

                              using std::swap;
                              swap(foo, CreateNewFoo());

                              Within templated code, of course, so foo could be either an STL container or a ThirdPartySpace::Foo. Would that be a motivating use case? (Oops, another shrug?)

                              > I've seen the motivation with wanting to swap
                              > with an rvalue container.

                              Old C++03 already supports swapping with an rvalue container! Albeit by calling the member swap of a temporary, of course...

                              > But over the past decade I haven't run across
                              > someone complaining that the general swap doesn't
                              > accept rvalues

                              Good point... although the introduction of rvalue references might significantly increase the use of rvalues! :-)

                              > You just would not believe the effort it takes
                              > to get a change through committee...

                              Okay, I believe you, I'm sorry! Still I tend to think that it would be better to either add rvalue reference support to std::swap for all possible types, or just remove those std::swap overloads from the STL containers as well.

                              Anyway, your replies are very helpful to me, getting an understanding of what rvalue references are about, so thanks again!
                            • Achilleas
                               
                              Posts: 98 / Nickname: achilleas / Registered: February 3, 2005 2:57 AM
                              Re: A Brief Introduction to Rvalue References
                              March 19, 2008 5:38 AM      
                              I've just read the stuff about unique_ptr...all I can say is 'whoa'.

                              In order to optimize STL 0.0000001 per cent, you just made this horrible mess of deleters, unique ptrs, rvalues, and the lot.

                              What's the point of all this?

                              C++ is fast enough as it is.

                              Due to lack of garbage collection, C++ is not used where stability and performance is important (for example, in web servers).

                              On the other hand, embedded software does not have a need so much sophisticated memory management techniques, simply because when resources are in shortage, static allocation is the preferred method of operation.

                              So what is left? desktop applications in C++...shared pointers are more than enough, and the extra ounce of performance gained by move semantics is insignificant for such applications.

                              Methinks the new move semantics in C++ are there just because you could do it, and for no other reason. Instead of introducing garbage collection and making all these move things, unique ptrs, auto ptrs, shared ptrs, deleters, reference traits etc a thing of the past, you insist on doing it the hard way.
                              • Ion
                                 
                                Posts: 8 / Nickname: igaztanaga / Registered: January 3, 2006 9:57 PM
                                Re: A Brief Introduction to Rvalue References
                                March 19, 2008 10:07 AM      
                                > I've just read the stuff about unique_ptr...all I can say
                                > is 'whoa'.
                                >
                                > In order to optimize STL 0.0000001 per cent, you just made
                                > this horrible mess of deleters, unique ptrs, rvalues, and
                                > the lot.
                                >
                                > What's the point of all this?

                                Read it again. Move semantics offer a "huge" speed improvement. Just try to use std::vector<string> with or wihout move semantics and you will see what I am talking about.

                                > C++ is fast enough as it is.

                                No, not fast enough.

                                > Due to lack of garbage collection, C++ is not used where
                                > stability and performance is important (for example, in
                                > web servers).

                                Achilleas. In every article, your reply is "we need garbage collection". Garbage collection work is underway, but I don't think it's necessary at all.

                                > On the other hand, embedded software does not have a need
                                > so much sophisticated memory management techniques, simply
                                > because when resources are in shortage, static allocation
                                > is the preferred method of operation.

                                I disagree. Embedded software will welcome move semantics precisely because it avoids memory allocation for many common operations. unique_ptr will be welcome because it offers reasonable leaking defense at ease of use for containers of pointers built to take advantage of polymorphism.
                                • Achilleas
                                   
                                  Posts: 98 / Nickname: achilleas / Registered: February 3, 2005 2:57 AM
                                  Re: A Brief Introduction to Rvalue References
                                  March 21, 2008 4:49 AM      
                                  > Read it again. Move semantics offer a "huge" speed
                                  > improvement. Just try to use std::vector<string> with or
                                  > wihout move semantics and you will see what I am talking
                                  > about.

                                  std::vector<string> is slow. QVector<QString> is not. It's seems that's a matter of implementation.

                                  >
                                  > > C++ is fast enough as it is.
                                  >
                                  > No, not fast enough.

                                  I have to disagree. There is nothing in the current C++ standard that prohibits from writing the fastest possible code. For example, if you want the fastest possible table of strings, you can write it in C++ as it is right now.

                                  >
                                  > > Due to lack of garbage collection, C++ is not used
                                  > where
                                  > > stability and performance is important (for example, in
                                  > > web servers).
                                  >
                                  > Achilleas. In every article, your reply is "we need
                                  > garbage collection". Garbage collection work is underway,
                                  > but I don't think it's necessary at all.

                                  Perhaps because you don't have to develop and maintain complex C++ applications.

                                  I've spend the last 5 years in 90% debugging and 10% developing C++ software, and 70% of the bugs were due to manual memory management (wild pointers, memory blocks deleted multiple times, arrays out of bounds etc).

                                  The lack of garbage collection in C++ has cost my company quite a lot.

                                  >
                                  > > On the other hand, embedded software does not have a
                                  > need
                                  > > so much sophisticated memory management techniques,
                                  > simply
                                  > > because when resources are in shortage, static
                                  > allocation
                                  > > is the preferred method of operation.
                                  >
                                  > I disagree. Embedded software will welcome move semantics
                                  > precisely because it avoids memory allocation for many
                                  > common operations. unique_ptr will be welcome because it
                                  > offers reasonable leaking defense at ease of use for
                                  > containers of pointers built to take advantage of
                                  > polymorphism.

                                  I do not question the need for more efficient abstractions in the case of embedded systems. What I do question is that the language needed changes in order to have these more efficient abstractions.

                                  The new features add significantly more complexity to an already-out-of-control complex language. If, in a few years, there is an outcry against move semantics because people can't get their programs to behave predictably (because data move around in a chaotic fashion), don't come back and say you haven't been warned.
                                • Nemanja
                                   
                                  Posts: 40 / Nickname: ntrif / Registered: June 30, 2004 1:10 AM
                                  Re: A Brief Introduction to Rvalue References
                                  March 19, 2008 10:43 AM      
                                  > Garbage collection work is underway,
                                  > but I don't think it's necessary at all.
                                  >

                                  IMHO, it is harmful. It would encourage people to stay away from value semantics and create more objects on the heap. On the contrary, we need rvalue references, not garbage collection. C++ is simply too low level language to afford GC.
                                  • Achilleas
                                     
                                    Posts: 98 / Nickname: achilleas / Registered: February 3, 2005 2:57 AM
                                    Re: A Brief Introduction to Rvalue References
                                    March 21, 2008 4:58 AM      
                                    > > Garbage collection work is underway,
                                    > > but I don't think it's necessary at all.
                                    > >
                                    >
                                    > IMHO, it is harmful. It would encourage people to stay
                                    > away from value semantics and create more objects on the
                                    > heap.

                                    No, it's not. I don't understand how you can claim that value semantics is all that's needed to write complex systems. In every sufficiently complex (i.e. non-trivial) program I have worked with (which was not very big or complex compared to really big projects), I could not have used value semantics for all the requirements.

                                    > On the contrary, we need rvalue references, not
                                    > garbage collection. C++ is simply too low level language
                                    > to afford GC.

                                    But GC works beautifully with C++! having studied GC systems extensively, I see no technical obstacle in having garbage collection in C++.

                                    I have to disagree with stubbornness against move semantics. The average coder will simply choke on it. Complex expressions like a.b(a, b.c(a)) will create intractable bugs where only the most experienced programmers will be able to understand.
                              • Bjarne
                                 
                                Posts: 48 / Nickname: bjarne / Registered: October 17, 2003 3:32 AM
                                Re: A Brief Introduction to Rvalue References
                                March 20, 2008 9:28 AM      
                                > C++ is fast enough as it is.

                                Many people disagree. In particular, if you want to write simple programs using value semantics, the cost of copying can become a problem. Rvalue references - which after all is the source of this particular debate - were introduced to transparently eliminate redundant copies. When used right (meaning under the covers of a class needing value semantics) they simply eliminate waste - they are an optimization mechanism. The problem they address is beyond the scope of current and likely near-future optimizers.


                                > Due to lack of garbage collection, C++ is not used where
                                > ...

                                C++ will get GC. GC is not a panacea, though, and about as many complain about the possibility of the ("useless, complex, and redundant") GC as do complain about its current absence.

                                I would have liked to see (programmer controlled) GC in C++0x, but I'll have to wait for a TR. IMO *many* will benefit from GC and *many* will live happily without using it even after it becomes standard.


                                > Methinks the new move semantics in C++ are there just
                                > because you could do it, and for no other reason.

                                You happen to be wrong about that. Rvalue references (move semantics) addresses a well known and significant problem with one of the most popular programming styles.
                                • Achilleas
                                   
                                  Posts: 98 / Nickname: achilleas / Registered: February 3, 2005 2:57 AM
                                  Re: A Brief Introduction to Rvalue References
                                  March 21, 2008 5:24 AM      
                                  > > C++ is fast enough as it is.
                                  >
                                  > Many people disagree. In particular, if you want to write
                                  > simple programs using value semantics, the cost of copying
                                  > can become a problem.

                                  If your program is so simple that it can only have value semantics, then it can be written in such a way that no copying is required. Copying is costly mainly when allocations are involved. If allocations are involved, then you don't have only value semantics, you also have reference semantics, albeit hidden.

                                  On the other hand, if your program is so sensitive in performance that it needs that extra ounce of efficiency gained by rvalues, then it's not that simple, is it? in that case, you will have already coded your algorithms in such a way that redundant copying would not exist.

                                  Rvalue references - which after all
                                  > is the source of this particular debate - were introduced
                                  > to transparently eliminate redundant copies. When used
                                  > right (meaning under the covers of a class needing value
                                  > semantics) they simply eliminate waste - they are an
                                  > optimization mechanism. The problem they address is beyond
                                  > the scope of current and likely near-future optimizers.

                                  But redundant copies exist because objects are allocated in scoped memory (i.e. the stack). Instead of fixing the source of the problem, you provided a patch, whereas fixing the problem will have solved a much greater spectrum of problems without introducing new ones.

                                  >
                                  >
                                  > > Due to lack of garbage collection, C++ is not used
                                  > where
                                  > > ...
                                  >
                                  > C++ will get GC. GC is not a panacea, though, and about as
                                  > many complain about the possibility of the ("useless,
                                  > complex, and redundant") GC as do complain about its
                                  > current absence.

                                  >
                                  > I would have liked to see (programmer controlled) GC in
                                  > C++0x, but I'll have to wait for a TR. IMO *many* will
                                  > benefit from GC and *many* will live happily without using
                                  > it even after it becomes standard.

                                  Why should they complain if it is optional? I do not claim that all C++ objects must be allocated on the heap. Stack allocation has important efficiency benefits, as well as RAII (very useful).

                                  >
                                  >
                                  > > Methinks the new move semantics in C++ are there just
                                  > > because you could do it, and for no other reason.
                                  >
                                  > You happen to be wrong about that. Rvalue references (move
                                  > semantics) addresses a well known and significant problem
                                  > with one of the most popular programming styles.

                                  RValue references addresses a well known and significant problem which would not have existed if other solutions were preferred in the first place. By insisting on manual memory management, the need to avoid copying arises, which in turn makes rvalues seem a good solution.

                                  Let me put it in this way: what needs to be moved with move semantics can be allocated on the heap using garbage collection and therefore all issues of language complexity and run-time efficiency, etc could be avoided.

                                  The inclusion of smart pointers in the standard library points to the need of automating the task of memory management.
                                  • Bjarne
                                     
                                    Posts: 48 / Nickname: bjarne / Registered: October 17, 2003 3:32 AM
                                    Re: A Brief Introduction to Rvalue References
                                    March 21, 2008 6:17 PM      
                                    > If your program is so simple that it can only have value
                                    > semantics, then it can be written in such a way that no
                                    > copying is required. ...
                                    >
                                    > On the other hand, if your program is so sensitive in
                                    > performance that it needs that extra ounce of efficiency
                                    > gained by rvalues, then it's not that simple, is it? ...
                                    >
                                    > But redundant copies exist because objects are allocated
                                    > in scoped memory (i.e. the stack). ...

                                    Telling people to to write (and rewrite) their code in the style you would have chosen is not an option.

                                    If nothing else, you may never have encountered the problems they set out to solve.


                                    > > I would have liked to see (programmer controlled) GC in
                                    > > C++0x, but I'll have to wait for a TR. IMO *many* will
                                    > > benefit from GC and *many* will live happily without
                                    > using
                                    > > it even after it becomes standard.
                                    >
                                    > Why should they complain if it is optional?

                                    But they do. Loudly. And they are not all inexperienced or stupid.


                                    > RValue references addresses a well known and significant
                                    > problem which would not have existed if other solutions
                                    > were preferred in the first place.

                                    But (many) people
                                    (1) don't agree and
                                    (2) do not prefer those other solutions
                                    (3) have lots of code written the way they like it
                                    • Achilleas
                                       
                                      Posts: 98 / Nickname: achilleas / Registered: February 3, 2005 2:57 AM
                                      Re: A Brief Introduction to Rvalue References
                                      May 27, 2008 4:17 AM      
                                      > > If your program is so simple that it can only have
                                      > value
                                      > > semantics, then it can be written in such a way that no
                                      > > copying is required. ...
                                      > >
                                      > > On the other hand, if your program is so sensitive in
                                      > > performance that it needs that extra ounce of
                                      > efficiency
                                      > > gained by rvalues, then it's not that simple, is it?
                                      > ...
                                      > >
                                      > > But redundant copies exist because objects are
                                      > allocated
                                      > > in scoped memory (i.e. the stack). ...
                                      >
                                      > Telling people to to write (and rewrite) their code in the
                                      > style you would have chosen is not an option.

                                      I would not like to make this a political issue. Sticking to the technological issues, my arguments are:

                                      1) GC makes it easier to write complex programs.
                                      2) GC makes it faster to write complex programs.
                                      3) if you take all factors into consideration, the addition of GC in C++ would benefit the language far more than rvalues, and it would make rvalues redundant. In other words, rvalues is there to solve a memory management issue, whereas a GC solves that issue and all the other related issues (no shared ptrs etc).

                                      >
                                      > If nothing else, you may never have encountered the
                                      > problems they set out to solve.
                                      >

                                      I don't think programs are very different, in essence. For example, we all have encountered the problem of sharing data between collections and other parts of the program. Common problems like are solved nicely by GC.

                                      If you have any examples of the problems that they set out to solve that are so different that rvalues is a better solution than garbage collection, then please feel free to share them with us.

                                      > > > I would have liked to see (programmer controlled) GC
                                      > in
                                      > > > C++0x, but I'll have to wait for a TR. IMO *many*
                                      > will
                                      > > > benefit from GC and *many* will live happily without
                                      > > using
                                      > > > it even after it becomes standard.
                                      > >
                                      > > Why should they complain if it is optional?
                                      >
                                      > But they do. Loudly. And they are not all inexperienced or
                                      > stupid.

                                      But you did not answer the question: why do they complain? the only reason I can see is stubbornness.

                                      >
                                      >
                                      > > RValue references addresses a well known and
                                      > significant
                                      > > problem which would not have existed if other solutions
                                      > > were preferred in the first place.
                                      >
                                      > But (many) people
                                      > (1) don't agree and
                                      > (2) do not prefer those other solutions
                                      > (3) have lots of code written the way they like it

                                      Arguments, please:

                                      1) Why they don't agree?
                                      2) what is the benefit of the other solutions?
                                      3) why can't they accept the fact that their code will run just as before, since the GC will be optional?
                                      • master
                                         
                                        Posts: 1 / Nickname: masterfish / Registered: June 8, 2008 5:39 PM
                                        Re: A Brief Introduction to Rvalue References
                                        June 8, 2008 10:54 PM      
                                        I think maybe 2 kind of cppers would not like GC
                                        [1].those work directly with hardware,and
                                        [2].those hate writting code just like java.
                                    • rgamarra79
                                       
                                      Posts: 7 / Nickname: rgamarra79 / Registered: September 26, 2008 3:00 AM
                                      Re: A Brief Introduction to Rvalue References
                                      October 1, 2008 4:35 PM      
                                      Jan,

                                      Thanks for your reply. Indeed, using the function template without specialization delegates a lot of work to the compiler in order to deduce the intended substitution.

                                      Your example and comments make clear how contrived the situation can be.

                                      Nevertheless, with my example maybe I changed the focus of my original question: What's the reason behind the usage of identity? So far, it seems to me that it only serves as a way to force the programmer to specialize his invocations of forward.

                                      Thanks a lot.

                                      Rodolfo.
                                      • Jan
                                         
                                        Posts: 4 / Nickname: janbessai / Registered: September 24, 2008 3:10 AM
                                        Re: A Brief Introduction to Rvalue References
                                        October 2, 2008 1:59 PM      
                                        Hi,
                                        it's pure speculation, but maybe the example was created using an incomplete compiler, which was not yet able to handle the
                                        template <typename T>
                                        void foo(T && bar) { ... } way correctly.
                                        I cannot imagine any other reason (despite habitual programming style). Specially as the identify-version is much harder to read and to understand.

                                        Jan.
    • Justin
       
      Posts: 1 / Nickname: jgottsch / Registered: December 21, 2004 7:20 PM
      Re: A Brief Introduction to Rvalue References
      October 29, 2008 11:04 AM      
      Hi,

      I personally have found rvalue references to be critically important for my research in software transactional memory.

      Here's a link to a paper we recently wrote that uses rvalue references for STM. It is invaluable for making it work correctly.

      http://eces.colorado.edu/~gottschl/pubs/icooolps08-exception.pdf

      Best Regards,
      Justin
    • Marc
       
      Posts: 1 / Nickname: marc77 / Registered: December 31, 2009 6:14 AM
      Re: A Brief Introduction to Rvalue References
      December 31, 2009 0:33 PM      
      I like rvalues because they offer an interesting way to optimize programs. But I think the standard could have been made better.

      First, in C you have restrict pointer. I believe C++0x should have tried to make rvalue references restricted.

      Second, how to make a better "move" and guarantee rvalue references are restricted? Simple with a new rule for the destructor:
      When the explicit destructor is called on a lvalue, the lvalue is destroyed but a copy is returned as a rvalue.

      Now, if you don't use the returned rvalue, the class destructor is called on it like for any other rvalue.

      Finally, I hope compilers will be able to automatically move a value when it is used for the last time or it's rvalue reference is used for the last time. This way, it would be possible to never use move and still receive most of the benefit from it.

      I would like to have comments, so I would know at least 1 person has read it(I know it is an old topic).

      Have a happy new year.
    • Achilleas
       
      Posts: 98 / Nickname: achilleas / Registered: February 3, 2005 2:57 AM
      Re: A Brief Introduction to Rvalue References
      October 12, 2010 4:24 AM      
      Hey, I was right after all: c++ move semantics created a problem for the STL library:

      http://cpp-next.com/archive/2010/10/implicit-move-must-go/

      In the above article, it is described how the move constructor chosen automatically over the copy constructor created a problem for a type that wasn't move-aware, i.e. the type assumed exclusive ownership of resources.

      I still think move semantics is a very bad idea. I expect that there are going to be lots of problems in the future, exactly as the one described in the article above.
    • White
       
      Posts: 4 / Nickname: wwolf / Registered: July 24, 2004 9:33 AM
      Re: A Brief Introduction to Rvalue References
      March 14, 2008 8:50 AM      
      Sorry for being off-topic... I don't want to talk about the complexity of C++, but about the actual article.

      I wonder how the heck can an article end up on Artima, signed by Bjarne and have a serious programming error in it???

      I talk about the exception safety of the clone_ptr assignment operator. Honestly, who write this article? What do the 10+ people on the editorial board do, if this gets published? Sorry for being upset a bit, but it may take literally *years* to "unteach" people who learn from material signed by Bjarne...

      So PLEASE, change this:

      clone_ptr& operator=(const clone_ptr& p)
      {
      if (this != &p)
      {
      delete ptr;
      ptr = p.ptr ? p.ptr->clone() : 0;
      }
      return *this;
      }

      to something like this:

      clone_ptr& operator=(const clone_ptr& p) {
      if (this == &p) return *this;
      T *ptrt== p.ptr ? p.ptr->clone() : 0;
      delete ptr;
      ptr=ptrt;
      return *this;
      }

      or any of the possible many variantions that won't leave clone_ptr::ptr point to 0xDEADBEEF if p.ptr->clone() throws...

      Attila aka ww
      • Bjarne
         
        Posts: 48 / Nickname: bjarne / Registered: October 17, 2003 3:32 AM
        Re: A Brief Introduction to Rvalue References
        March 14, 2008 6:09 PM      
        >
        > I wonder how the heck can an article end up on Artima,
        > signed by Bjarne and have a serious programming error in
        > it???
        >

        By being a simple copy of a standards document focussed on a single topic written for relative experts. I would like to have had time to write a "perfect" article aimed for a more general audience, but there were no time and much demand.

        -- Bjarne Stroustrup; http://www.research.att.com/~bs

        and of course: sorry.
        • White
           
          Posts: 4 / Nickname: wwolf / Registered: July 24, 2004 9:33 AM
          Re: A Brief Introduction to Rvalue References
          March 15, 2008 10:35 AM      
          Phew. No I know that it wasn't someone else using your name(s). And I perfectly understand the reasons for the mistake. I am just very sorry that nobody has caught it in review and it has been published.

          As usual: I did not intend to come through as an A-hole... and yet I succeeded. And unfortunately cheating does not work in my communication impairment: if I want to sound like one, I do then too. ;)

          As for the time issue. I do not expect to be on the board or even mentioned, but I would be grateful if I would get the chance to quickly review stuff before it gets published. IOWs I volunteer, if anyone needs me. I am no guru or authority, but I have the advantage of knowing (hopefully enough) C++ and have no life... well, advantage for reviewing time anyway. :)

          I am in Shanghai again until near the end of August, and due to that I won't be showing up on meetings until the fall.

          I like Howards' example of the "quick fix", although I am not sure it is a good idea to delete the data if we are unable to copy it... In such a generic component we cannot tell if it was crucial to the program or not. Anyway, do you think it would be possible to update the article to provide some level of exception safety? I don't know how Artima works, but if it is possible, it would be valuable. IMHO.
      • Howard
         
        Posts: 9 / Nickname: hinnant / Registered: December 16, 2007 7:49 AM
        Re: A Brief Introduction to Rvalue References
        March 14, 2008 3:55 PM      
        > I wonder how the heck can an article end up on Artima,
        > signed by Bjarne and have a serious programming error in
        > it???
        >
        > I talk about the exception safety of the clone_ptr
        > assignment operator. Honestly, who write this article?

        I did. And you are correct that there is an exception safety bug in this assignment operator. My apologies.

        This paper was originally a committee paper aimed at getting this language feature accepted, and not targeted to Artima. This detail was not important to the original goal of the paper.

        > What do the 10+ people on the editorial board do, if this
        > s gets published?

        They work hard at their day jobs and volunteer what little time they have left over (if any).

        > So PLEASE, change this:
        >
        > clone_ptr& operator=(const clone_ptr& p)
        > {
        > if (this != &p)
        > {
        > delete ptr;
        > ptr = p.ptr ? p.ptr->clone() : 0;
        > }
        > return *this;
        > }
        >
        > to something like this:
        >
        > clone_ptr& operator=(const clone_ptr& p) {
        > if (this == &p) return *this;
        > T *ptrt== p.ptr ? p.ptr->clone() : 0;
        > delete ptr;
        > ptr=ptrt;
        > return *this;
        > }

        I would have no objections to this change. Another acceptable possibility is:

        clone_ptr& operator=(const clone_ptr& p)
        {
        if (this != &p)
        {
        delete ptr;
        ptr = 0;
        ptr = p.ptr ? p.ptr->clone() : 0;
        }
        return *this;
        }
        • Gaetano
           
          Posts: 1 / Nickname: kalman / Registered: November 1, 2010 7:22 AM
          Re: A Brief Introduction to Rvalue References
          November 1, 2010 0:27 PM      
          > I would have no objections to this change. Another
          > acceptable possibility is:
          >
          > clone_ptr& operator=(const clone_ptr& p)
          > {
          > if (this != &p)
          > {
          > delete ptr;
          > ptr = 0;
          > ptr = p.ptr ? p.ptr->clone() : 0;
          > }
          > return *this;
          > }

          For my taste this is still not acceptable, the code above still destroy the old class instance if the clone throws. Better the previous suggested change.
    • Walter
       
      Posts: 12 / Nickname: wkaras / Registered: December 22, 2003 2:53 PM
      Re: A Brief Introduction to Rvalue References
      May 26, 2012 7:46 PM      
      Consider this code:

      extern void foo(A &a);
      extern void foo(A &&a);

      void bar(void)
      {
      A a,*ap = new A;

      foo(*ap);
      delete ap;

      foo(a);
      }

      Would the compiler be required or allowed to use the second overload of foo() for either of the two calls to foo() in bar() ?

      Separate question: was consideration given to requiring functions that take a rvalue reference to be equivalent to an explicit destructor call on the object? And, in a question related to that question, does/should the Standard require that this:

      ap->~A();
      delete static_cast<void *>(ap);

      work?
      • Niels
         
        Posts: 9 / Nickname: dekker / Registered: September 7, 2006 6:14 AM
        Re: A Brief Introduction to Rvalue References
        May 26, 2012 11:24 PM      
        Walter Karas wrote:
        > Consider this code:
        >
        > extern void foo(A &a);
        > extern void foo(A &&a);
        >
        > void bar(void)
        > {
        > A a,*ap = new A;
        >
        > foo(*ap);
        > delete ap;
        >
        > foo(a);
        > }
        >
        > Would the compiler be required or allowed to use the
        > second overload of foo() for either of the two calls to
        > foo() in bar() ?

        No. 'a' and '*ap' are not rvalues, so in your example, foo(A&&a) will never be called.


        > Separate question: was consideration given to requiring
        > functions that take a rvalue reference to be equivalent to
        > an explicit destructor call on the object? And, in a
        > question related to that question, does/should the
        > Standard require that this:
        >
        > ap->~A();
        > delete static_cast<void *>(ap);
        >
        > work?

        I guess N1377 section "Alternative move designs" might be of help to you:
        http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm#Alternative%20move%20designs

        Happy programming!

        -- Niels
        • Walter
           
          Posts: 12 / Nickname: wkaras / Registered: December 22, 2003 2:53 PM
          Re: A Brief Introduction to Rvalue References
          May 28, 2012 7:41 AM      
          > Walter Karas wrote:
          > > Consider this code:
          > >
          > > extern void foo(A &a);
          > > extern void foo(A &&a);
          > >
          > > void bar(void)
          > > {
          > > A a,*ap = new A;
          > >
          > > foo(*ap);
          > > delete ap;
          > >
          > > foo(a);
          > > }
          > >
          > > Would the compiler be required or allowed to use the
          > > second overload of foo() for either of the two calls to
          > > foo() in bar() ?
          >
          > No. 'a' and '*ap' are not rvalues, so in your example,
          > foo(A&&a) will never be called.

          Could it be forced like this?

          foo(static_cast<A &&>(*ap));

          foo(static_cast<A &&>(a));

          >
          >
          > > Separate question: was consideration given to
          > requiring
          > > functions that take a rvalue reference to be equivalent
          > to
          > > an explicit destructor call on the object? And, in a
          > > question related to that question, does/should the
          > > Standard require that this:
          > >
          > > ap->~A();
          > > delete static_cast<void *>(ap);
          > >
          > > work?
          >
          > I guess N1377 section "Alternative move designs" might be
          > of help to you:
          > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n13
          > 77.htm#Alternative%20move%20designs
          >
          > Happy programming!
          >
          > -- Niels
    • Roman
       
      Posts: 1 / Nickname: romanl / Registered: December 16, 2014 4:31 AM
      Re: A Brief Introduction to Rvalue References
      December 16, 2014 10:40 AM      

      A a;
      A&& a_ref2 = a; // an rvalue reference

      This example from the article wouldn't compile with current compilers. Did things change and the article should be considered outdated?