Re: Another approach to forward/move issues
In article <etdta0$vqi$1@aioe.org>, grizlyk1@yandex.ru ("Grizlyk")
wrote:
template<class T>
T moveable boo(const T moveable t)
In the example "t" is "value" - new value of caller parameter of "T" type.
Also "boo" declared as returning value created by "move constructor" instead
of "copy constructor".
{
//here end of "t" life-time
T moveable tmp(t);
tmp = 3;
//here end of "tmp" life-time
return tmp;
}
template <class T>
T boo(T&& t)
No, no, no. You are contradicts youself. Previously we have assumed that
"T&&" means: "t" is address of exernal "T", but now you are trying to
express with "T&&" value of exernal "T", you are trying to express
"sizeof(T)" with the help of "sizeof(T*)" - it is impossible.
Between the human language difference and the proposal syntax
difference, we are all struggling with clear communication. From your
comments above I believe the correct syntax transformation would just be:
template <class T>
T boo(T t)
{ ...
You are correct that an rvalue reference is just like our existing
reference today in that it is just a pointer underneath.
{
T tmp(std::move(t));
tmp = 3;
return tmp;
You just can not do "return tmp", because T::T(const T&) is private in this
context - T is moveable only.
This is one of the key ideas from the current proposal that you are
missing, and this is likely my fault as it was not clearly described in
the "brief introduction" paper. Please see:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm#Moving%
20from%20local%20values
This explains that in the cases where RVO is legal by today's rules,
there is effectively an implicit cast to rvalue on the return statement.
Thus in the example above, if T has a move constructor, that is what is
used to "copy" tmp out of boo(). This move may be elided via RVO. If T
does not have a move constructor, but does have a copy constructor, then
that will be used, or elided.
The logic resulting from this implicit cast results in an automatic
hierarchy of "move semantics" from best to worst:
* If you can elide the move/copy, do so (by present language rules)
* Else if there is a move constructor, use it
* Else if there is a copy constructor, use it
* Else the program is ill formed
This enables types which are not copyable, but are movable, to be
returned from functions by value.
unique_ptr<int> p1;
unique_ptr<int> p2 = p1; // compile time error
unique_ptr<int> make_unique_ptr(); // function prototype
unique_ptr<int> p3 = make_unique_ptr(); // ok
This allows the return value
optimisation, which is more efficient than a move.
What is "the return value optimisation" and "move"?
RVO (return value optimization) is a license granted by the C++98
standard to avoid executing the copy constructor (in some cases) when a
value is returned from a function.
I really suspect that we are much more in agreement than we realize. We
are differing in syntax, backwards compatibility concerns, generic
coding concerns, etc. But we have also come to some similar conclusions.
a =< b;
This is actually the very syntax I first came up with too! :-) Daveed
Vandevoorde was kind enough to point out to me nearly 6 years ago:
On Jun 1, 2001, at 2:46 PM, Daveed Vandevoorde wrote:
To: C++ extensions mailing list
Message c++std-ext-4128
Howard Hinnant wrote:
[...]
struct A
{
???????A=<(A&) throw();
???????A& operator=<(A&) throw();
I think the syntax will need revision. ?Since core issue 38 became a DR,
the sequence 'operator=<' can be the beginning of a template-id that
refers to a specialization of an operator= template.
? ?Daveed
It was John Maddock who first suggested the current syntax just a day
later:
On Jun 2, 2001, at 7:29 AM, John Maddock wrote:
A a1;
A a2(move(a1));
a1 = move(a2);
Some major points:
* Compile time detection of double-move is not realistic. It simply
can not be done reliably enough in real world use cases. The original
proposal recognizes this fact, and the danger of the double-move by
requiring syntax other than copy for all moves except when it is not
possible to get into a double-move situation. Thus programmers can more
easily audit their code for double-moves:
a = std::move(b);
..
c = std::move(b); // this is greppable
* We can't just change auto_ptr such that:
auto_ptr<A> p1;
auto_ptr<A> p2 = p1;
stops compiling. Yes, we would like to do that. No we can't. Vendors
would go out of business if they tried. So we have to "fix" auto_ptr by
starting over with a new name.
* Generic algorithms need to work with types that are:
- only have copy constructors
- have both move and copy constructors
and we want many algorithms to work with type that:
- have only move constructors
It isn't realistic to require overloaded generic algorithms for these
cases. The same templated code needs to work for copyable types as
move-only types. For example we want both:
vector<unique_ptr<int>> and vector<string> to not require two completely
different implementations of vector. And if you take that vector and
run over it with std::remove, the same algorithm ought to work for both.
* I think it is unwise to move from const-qualified types. A move is
allowed to change the source. If you declare something const, then you
are saying you don't want it changed.
-Howard
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]