C++0x: move() & a hypotheticyl language feature
Hi!
The latest declaration of std::move according to N2798 is
template<RvalueOf T> RvalueOf<T>::type move(T&&);
where RvalueOf is defined to be
auto concept RvalueOf<typename T> {
typename type = T&&;
require Convertible<T&,type> && Convertible<T&&,type>;
}
template<typename T> concept_map RvalueOf<T&> {
typedef T&& type;
}
But a move is only interesting when the parameter is actually an
lvalue. In case of a rvalue parameter the function might return a
reference that's going to dangle once the evaluation of the expression
is completed. Example:
A&& aref = move(A()); // 'a' will be a dangling reference
This is because the information about the returned reference being a
local temporary is LOST. So, i was thinking whether it's okay to
replace the current move by a function like this:
template<typename T> T&& move(T& x) { return x; }
template<typename T> T&& move(T&&) = delete;
This, will restrict the applicability of move to lvalues. For rvalues
we simply don't need 'move' because the only purpose of move is to
return an rvalue. The question is: Is there any drawback in having
'move' work on lvalues only?
Disclaimer: I'm going to describe a *hypothetical* language feature
that solves these kinds of "dangling reference" problems. This is not
a proposal for C++0x.
I was thinking about a way to save the information that a certain
reference references a local temporary object. Example:
string&& operator+(string&& a, string const& b) {
a += b; return a;
}
string && a = string("hello") + string("world");
'a' is initialized to refer to the temporary object string("hello")
which has been altered by operator+. But extenting the object's life-
time is made impossible because the compiler doesn't know what
reference operator+ will be returning unless it inspects the
function's body. Suppose, we have a way of declaring that a function
returns a reference to one of the given argument references:
string&& operator+(string&& a : return, string const& b);
In this case the compiler would know exactly what reference is
returned by the function: it's a reference to the local temporary
object string("hello"). This is kown at compile-time. The function
body would be ill-formed if the return statement doesn't match the
declaration's promise. So, the life-time extension rule we have in C+
+98 can be applied to this object to avoid danling references. A
corresponding move() could look like this:
template<RvalueOf T> RvalueOf<T>::type move(T&& x : return)
{ return x; // returning anything else would be ill-formed }
which keeps the following line
A&& aref = move(A()); // compiler knows what 'aref' will be ref'ing
well-formed AND safe as it can apply the life-time extension rule. For
non-static member functions that contain "return *this;" the
declaration could be
class A {
// ...
A& operator+=(A const& x) : return;
};
A& A::operator+=(A const& x) : return
{
member += x.member;
return *this; // returning anything else would be ill-formed
}
This feature would reduce the danger of dangling references and make
other optimizations possible. For example:
- reference doesn't need to be implemented via pointer (we already
know the function's answer)
- allows safe manipulation and recycling of temporary objects
- renders every function of the form T&& f(T&& : return);
automatically safe with respect to object life-times.
Especially in the presence of rvalue references the ability to express
that a function always returns a reference to a specific reference-
parameter seems like a good complement to the life-time extension
rule.
Opinions?
Cheers!
SG
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]