Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r50192 - sandbox/committee/rvalue_ref
From: dgregor_at_[hidden]
Date: 2008-12-08 10:45:11


Author: dgregor
Date: 2008-12-08 10:45:10 EST (Mon, 08 Dec 2008)
New Revision: 50192
URL: http://svn.boost.org/trac/boost/changeset/50192

Log:
Some minor edits
Text files modified:
   sandbox/committee/rvalue_ref/n2812_08-0322_soundness.rst | 58 ++++++++++++++++++++++++---------------
   1 files changed, 35 insertions(+), 23 deletions(-)

Modified: sandbox/committee/rvalue_ref/n2812_08-0322_soundness.rst
==============================================================================
--- sandbox/committee/rvalue_ref/n2812_08-0322_soundness.rst (original)
+++ sandbox/committee/rvalue_ref/n2812_08-0322_soundness.rst 2008-12-08 10:45:10 EST (Mon, 08 Dec 2008)
@@ -86,7 +86,6 @@
   reasons I'm not sure if that vote had any legal force, so we may
   need to do something about it.
 
-
 -----------------
  Written Section
 -----------------
@@ -94,10 +93,12 @@
 Synopsis
 ========
 
-This paper describes a safety problem with rvalue references. The underlying
-issue has been known for some time, but recently-discovered examples have made
-its seriousness much more apparent. We also propose a solution to the
-problem, which has been implemented in the GNU C++ compiler.
+This paper describes a safety problem with rvalue references, where
+code can inadvertently move resources from lvalues. The underlying
+issue has been known for some time, but recently-discovered examples
+have made its seriousness much more apparent. We also propose a
+solution to the problem, which has been implemented in the GNU C++
+compiler.
 
 The Killer Example
 ==================
@@ -105,7 +106,7 @@
 The example that made this safety problem with rvalue references
 critical involves both rvalue references and concepts. The simplest
 example is the conceptualized version of the ``push_back`` functions
-in ``std::list``::
+in, e.g., ``std::list``::
 
   requires CopyConstructible<value_type>
   void push_back(const value_type& a); // #1: copies a
@@ -125,6 +126,12 @@
     lx.push_back(a); // oops: 'a' no longer has its original value
   }
 
+Rvalue references were formulated to make the operation "move a value
+from ``x``" safe (in the case of temporary values) or explicit
+(users must write ``std::move(x)``). However, the example above
+illustrates that one can subvert the intended safety without an
+explicit ``std::move``.
+
 What Happened?
 ==============
 
@@ -209,7 +216,7 @@
 this change, given just a single function template ``enqueue``::
 
   template <class T, typename Cont>
- void enqueue(queue<T, Cont>& dest, queue<T, Cont>&& src); // #1
+ void enqueue(queue<T, Cont>& dest, queue<T, Cont>&& src); // #3
 
 calling ``enqueue`` with an rvalue succeeds while calling it with an
 lvalue fails::
@@ -226,7 +233,7 @@
 
   template <class T, typename Cont>
   void enqueue(queue<T, Cont>& dest, const queue<T, Cont>& src,
- typename Cont::allocator_type alloc = typename Cont::allocator_type()); // #2
+ typename Cont::allocator_type alloc = typename Cont::allocator_type()); // #4
   
 Now, if we attempt to enqueue elements from an lvalue where the
 queue's container does not have an allocator, we receive an error
@@ -234,8 +241,8 @@
 silently moving from lvalue::
 
   void g(queue<int, simple_list<int>>& dest, queue<int, simple_list<int>>& src) {
- enqueue(dest, src); // error: #1 cannot be called because src isn't an lvalue
- // #2 fails template argument deduction
+ enqueue(dest, src); // error: #3 cannot be called because src isn't an lvalue
+ // #4 fails template argument deduction
   }
 
 Impact on Users
@@ -258,10 +265,10 @@
   requires MoveConstructible<value_type>
     void push_back(value_type&& x); // moves x
 
-For a move-only type ``X``, the first `push_back` will be eliminated
+For a move-only type ``X``, the first ``push_back`` will be eliminated
 because template argument deduction fails (``X`` does not meet the
 ``CopyConstructible`` requirements), and the second ``push_back``
-only accepts rvalues. Hence, calling `push_back` with an lvalue of
+only accepts rvalues. Hence, calling ``push_back`` with an lvalue of
 move-only type ``X`` will result in an error.
 
 The proposed change also does not have any impact on the use
@@ -314,9 +321,9 @@
 Impact on the Standard Library
 ------------------------------
 
-The changing in the binding of rvalue references affects the standard
+The change in the binding of rvalue references affects the standard
 library in four different areas: the definitions of ``std::move`` and
-``std::forward``, the definition of member ``swap``s, the formulation
+``std::forward``, the definition of member ``swap``, the formulation
 of the stream insertion/extraction operators, and the description of
 the ``Iterator`` concept.
 
@@ -338,7 +345,7 @@
      inline typename std::remove_reference<T>::type&& move(T&& x)
      { return static_cast<typename std::remove_reference<T>::type&&>(x); }
 
-''std::forward'' relies on the binding of lvalues to rvalue references
+``std::forward`` relies on the binding of lvalues to rvalue references
 in its argument type, since it is typically invoked with lvalues::
 
    template<typename T>
@@ -360,7 +367,8 @@
 
    template<typename T>
      inline typename disable_if<is_lvalue_reference<T>, T&&>::type
- forward(typename std::identity<T>::type&& x) { return x; }
+ forward(typename std::identity<T>::type&& x)
+ { return static_cast<T&&>(x); }
   
 Note that, with these changes to both ``std::move`` and
 ``std::forward``, the idiomatic uses of these functions still work, so
@@ -398,7 +406,7 @@
 
 With our proposed change to rvalue references, each of the stream
 insertion and extraction operators will need to use an lvalue
-reference to their stream argument to bind to lvalues streams,
+reference to their stream argument to bind to lvalue streams,
 effectively reverting streams to their C++03 behavior::
 
   template<class charT, class traits, class Allocator>
@@ -467,8 +475,8 @@
 check whether the binding computed would bind an lvalue to an rvalue
 reference, and reject the binding in this case. The changes to the
 standard library are slightly more involved, because we needed to
-implement the changes described in the section 'Impact on the Standard
-Library'_. We do not anticipate that this change will have any
+implement the changes described in the section `Impact on the Standard
+Library`_. We do not anticipate that this change will have any
 significant impact on compilers or standard library
 implementations. The GCC implementation required a day's effort to
 update both the language and the library, although more effort would
@@ -506,7 +514,7 @@
 from the set. So why does it happen here?
 
 In C++03 overload sets where only one overload mutates data (see
-set<T>::operator[]), the mutating operation always binds less-liberally to
+``set<T>::operator[]``), the mutating operation always binds less-liberally to
 arguments than the non-mutating operation. Non-const operations never attract
 const arguments. Rvalue references, however, *will* attract lvalues,
 so the removal of an overload can change an (apparently) non-mutating
@@ -539,7 +547,7 @@
   void swap(mytype&& other) { swap(other); }
 
 If there were multiple parameters that could be either lvalues or
-rvalues, the number of required overloads would grow expentially. For
+rvalues, the number of required overloads would grow exponentially. For
 example, a non-member ``swap`` that supports all combinations of lvalues
 and rvalues would go from::
 
@@ -552,7 +560,11 @@
   void swap(mytype&& x, mytype& y) { swap(x, y); }
   void swap(mytype&& x, mytype&& y) { swap(x, y); }
 
-To address this issue, one could extend our proposed resolution to
+At this point, we know of no use cases that would involve more than
+two parameters that can either be lvalues or rvalues, other than those
+that are actually versions of perfect forwarding (and which are,
+therefore, not affected by the proposed change). Nonetheless, to
+address this issue, one could extend our proposed resolution to
 support a third kind of reference (spelled ``&&&``) that binds to
 either lvalues or rvalues, effectively providing the current behavior
 of ``&&`` but with a new spelling. Thus, the above swap could be written
@@ -618,7 +630,7 @@
 in those cases where the concept requirements of a template are not
 satisfied but SFINAE does not eliminate the template from
 consideration. For example, it does not solve the problem with the
-``enqueue`` function described above (which doesn't involve concepts):
+``enqueue`` function described above (which doesn't involve concepts)::
 
   template <class T, typename Cont>
     void enqueue(queue<T, Cont>& dest, queue<T, Cont>&& src); // #1


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk