Topic: Another approach to forward/move issues
Author: dave@boost-consulting.com (David Abrahams)
Date: Tue, 20 Mar 2007 04:01:24 GMT Raw View
on Fri Mar 16 2007, grizlyk1-AT-yandex.ru ("Grizlyk") wrote:
> tasjaevan@gmail.com wrote:
>>>
>>> Tell me please, "r-value reference" is "moveable reference" or "moveable
>>> value"? There are great differences between "value" and "reference" data
>>> types in C++. Any "reference" is always address "sizeof(r-value
>>> reference)==sizeof(reference)". What "sizeof(T&&)" is? Consider
>>> _simplest_
>>> example with moveable:
>>>
>>
>> An r-value reference is mostly identical to a regular (lvalue)
>> reference. It doesn't directly mean 'moveable', but it does enable
>> move semantics.
>
> I just can repeat (and sure, most C++ programmers agree with me) that
> reference is not the same as value and you never can invent any kind of
> "special reference" to be simultaneously "value" and "reference" for any
> kind of semantics.
When Howard writes "regular (lvalue) reference" you can read it simply
as "reference as defined in C++98." You shouldnt' be distracted by
the appearance of the word "value" in "lvalue." That's merely a way
of reminding ourselves that C++98 references are treated as (and
indistinguishable from ) lvalues in most contexts.
> At least for "move semantics" we have sharp differences between "moveable
> passed by reference" and "moveable passed by value" (see
> http://grizlyk1.narod.ru/cpp_new #11..#15)
rvalue references indicate "pass by reference"
> and removing from C++ manual
> control of "what kind of parameter will be used" is very wrong idea,
> contradicting to all other parts of C++.
No such removal of control exists in the rvalue reference feature.
>> I've translated your examples below (but real world
>> examples would be better than snippets of syntax).
>
> My dictionary of 8000 popular english words does not contain
> "snippets", but it does not metter here, because the question "what
> kind of syntax is better" is topic to discuss here. It is not a
> thread named "Collection of words of love to r-value reference" or
> "R-value reference is Only True moveable semantic representation in
> the world".
Wow, attitudinal! (also not in your english dictionary)
>>> template<class T>
>>> void foo(T moveable& t)
>
> In the example "t" is "reference" - address of caller parameter of "T" type.
> Will be allocated "sizeof(T*)" memory, not "sizeof(T)".
>
>>> {
>>> t = 3;
>>> //here _no_ end of "t" life-time
>>>
>>> }
>>>
>>
>> template <class T>
>> void foo(T&& t)
>> {
>> t = 3;
>> }
>
> And what is "T&& t" implementation? Is "t" address of exernal "T" or
> copy of value of "T"? What size of memory i must allocated on stack
> for "foo" to place parameter?
>
> Using semantics of term "reference" i am assuming "T&&" means: "t" is
> address of exernal "T". Will be allocated "sizeof(T*)" memory, not
> "sizeof(T)".
Correct.
>>> 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".
Does that information belong in the declaration? It is not very
useful to the caller of the function, is it?
>>> {
>>> //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.
Howard does not contradict himself; it seems he's merely attempting to
produce a function with semantics identical to what he supposes your
"boo" is intended to do. The rvalue reference proposal recognizes
that one can implement the same semantics as a moveable value
parameter (at least, by my interpretation of what you mean by
"moveable value) by manually moving from an rvalue reference
parameter, so it uses only one language feature (rvalue reference)
rather than specifying moveable value and moveable reference.
>> {
>> 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.
Actually with the rvalue reference feature, a "moveable only" type can
be returned as above; the compiler just moves it. In fact, all types
are returned by move (where move devolves to copy if there's no move
constructor available). So, yes, you can just do "return tmp."
>> }
>>
>> The value return type is deliberate.
>
> What does "deliberate" mean in the context? Really, do not
> understand any in the sentence.
It means that Howard understood that you meant to move the return
value, and he replicated those semantics without needing to complicate
the return type of his function with a "moveable" notation.
>>> template<class T>
>>> moveable T voo()
>>> {
>>> moveable T x;
>>> foo<T>(x);
>>> //here end of "x" life-time and reassignment of "x"
>>> x=boo<T>(x);
>>> //here end of "x" life-time
>>> return x;
>>>
>>> }
>>>
>>
>> template <class T>
>> T voo()
>> {
>> T x;
>> foo<T>(std::move(x));
>> x = boo<T>(x); // no std::move required here, since boo returns by
>> value
>> return x;
>
> Again: You just can not do "return tmp", because T::T(const T&) is private
> in this context - T is moveable only.
Except that you can.
>>> What does "std::move" mean?
>>
>> It simply turns the expression into an rvalue.
>
> What "rvalue" property are you using here?
The one defined in the standard. More specifically, std::move takes
an (regular C++98, lvalue) reference argument and returns it as an
rvalue reference. As a result, the compiler can treat that reference
as an rvalue, including being able to move from it.
> Do not forget - you need allocate concrete size of memory for
> functions and variables and there is no any "sizeof(rvalue)" defined
> in C++.
I'm not sure what you're claiming, but the expression
5
is an rvalue, and
sizeof(5)
certainly has meaning in C++.
>>> T y;
>>> T x;
>>> x=std::move(y);
>>>
>>> I see here two explicit operations:
>>>
>>> x.operator=( from std::move<T>_return_value )
>>>
>>
>> No, std::move only affects the rvalue-ness of the expression. It does
>> nothing by itself.
>
> What is "rvalue-ness" of any expression?
See the C++ standard.
> What implementation of "std::move" must be to do "rvalue-ness"?
See
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html:
template <class T>
inline
typename remove_reference<T>::type&&
move(T&& t)
{
return t;
}
[ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html#A%20Minor%20Error%20in%20N1377
explains the use of remove_reference ]
> I am guessing, "std::move" is going to explicitly try to tell to compiler
> that "move assignment/constructor" must be used insted of "copy
> one".
Replace "must" with "can," and you have it right.
> But what to do with implicit assignment/constructions with move
> semantics?
I don't understand the question.
>> Why don't you read the proposal? In fact, it's a
>> single operation: T's move assignment operator.
>
> I read it many times but can not understand it because either
> semantics of used terms contradicts to the same ordinary C++ terms
Which terms? If you ask specific questions, I'm sure someone can
clarify things for you.
> or i even can not imaging how a property of so simple thing as
> "moveable balue and reference" can be implemented in the proposal
> even in theory.
I think you would have to very clearly explain what you mean by
"movable value and reference" before anyone should try further to map
the proposal onto those concepts.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
---
[ 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 ]
Author: tasjaevan@gmail.com
Date: Tue, 20 Mar 2007 10:06:49 CST Raw View
On Mar 20, 4:01 am, d...@boost-consulting.com (David Abrahams) wrote:
> on Fri Mar 16 2007, grizlyk1-AT-yandex.ru ("Grizlyk") wrote:
> > tasjae...@gmail.com wrote:
>
> >> An r-value reference is mostly identical to a regular (lvalue)
> >> reference. It doesn't directly mean 'moveable', but it does enable
> >> move semantics.
>
> > I just can repeat (and sure, most C++ programmers agree with me) that
> > reference is not the same as value and you never can invent any kind of
> > "special reference" to be simultaneously "value" and "reference" for any
> > kind of semantics.
>
> When Howard writes "regular (lvalue) reference" you can read it simply
> as "reference as defined in C++98."
The quoted text was mine, not Howard's, incidentally. Thanks for the
clarification :-)
James
---
[ 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 ]
Author: grizlyk1@yandex.ru ("Grizlyk")
Date: Fri, 16 Mar 2007 14:13:07 GMT Raw View
tasjaevan@gmail.com wrote:
>>
>> Tell me please, "r-value reference" is "moveable reference" or "moveable
>> value"? There are great differences between "value" and "reference" data
>> types in C++. Any "reference" is always address "sizeof(r-value
>> reference)==sizeof(reference)". What "sizeof(T&&)" is? Consider
>> _simplest_
>> example with moveable:
>>
>
> An r-value reference is mostly identical to a regular (lvalue)
> reference. It doesn't directly mean 'moveable', but it does enable
> move semantics.
I just can repeat (and sure, most C++ programmers agree with me) that
reference is not the same as value and you never can invent any kind of
"special reference" to be simultaneously "value" and "reference" for any
kind of semantics.
At least for "move semantics" we have sharp differences between "moveable
passed by reference" and "moveable passed by value" (see
http://grizlyk1.narod.ru/cpp_new #11..#15) and removing from C++ manual
control of "what kind of parameter will be used" is very wrong idea,
contradicting to all other parts of C++.
> I've translated your examples below (but real world
> examples would be better than snippets of syntax).
My dictionary of 8000 popular english words does not contain "snippets", but
it does not metter here, because the question "what kind of syntax is
better" is topic to discuss here. It is not a thread named "Collection of
words of love to r-value reference" or "R-value reference is Only True
moveable semantic representation in the world".
>
>> template<class T>
>> void foo(T moveable& t)
In the example "t" is "reference" - address of caller parameter of "T" type.
Will be allocated "sizeof(T*)" memory, not "sizeof(T)".
>> {
>> t = 3;
>> //here _no_ end of "t" life-time
>>
>> }
>>
>
> template <class T>
> void foo(T&& t)
> {
> t = 3;
> }
And what is "T&& t" implementation? Is "t" address of exernal "T" or copy of
value of "T"? What size of memory i must allocated on stack for "foo" to
place parameter?
Using semantics of term "reference" i am assuming "T&&" means: "t" is
address of exernal "T". Will be allocated "sizeof(T*)" memory, not
"sizeof(T)".
>
>> 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.
> {
> 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.
> }
>
> The value return type is deliberate.
What does "deliberate" mean in the context? Really, do not understand any in
the sentence.
> This allows the return value
> optimisation, which is more efficient than a move.
What is "the return value optimisation" and "move"?
>
>> template<class T>
>> moveable T voo()
>> {
>> moveable T x;
>> foo<T>(x);
>> //here end of "x" life-time and reassignment of "x"
>> x=boo<T>(x);
>> //here end of "x" life-time
>> return x;
>>
>> }
>>
>
> template <class T>
> T voo()
> {
> T x;
> foo<T>(std::move(x));
> x = boo<T>(x); // no std::move required here, since boo returns by
> value
> return x;
Again: You just can not do "return tmp", because T::T(const T&) is private
in this context - T is moveable only.
> }
>
>
>>
>> > Even with the current syntax, I think we have a challenge finding how
>> > to teach && references, so that this seems natural.
>>
>> > The way I think of it is that && references are only relevant in
>> > parameter lists, return types and casts (although std::move and
>> > std::forward should be used instead of casts).
>>
>> What does "std::move" mean?
>>
>
> It simply turns the expression into an rvalue.
What "rvalue" property are you using here? Do not forget - you need allocate
concrete size of memory for functions and variables and there is no any
"sizeof(rvalue)" defined in C++.
>> T y;
>> T x;
>> x=std::move(y);
>>
>> I see here two explicit operations:
>>
>> x.operator=( from std::move<T>_return_value )
>>
>
> No, std::move only affects the rvalue-ness of the expression. It does
> nothing by itself.
What is "rvalue-ness" of any expression? What implementation of "std::move"
must be to do "rvalue-ness"?
I am guessing, "std::move" is going to explicitly try to tell to compiler
that "move assignment/constructor" must be used insted of "copy one". But
what to do with implicit assignment/constructions with move semantics?
>
>> Note, it is not the same as
>>
>> T y;
>> T moveable x;
>> x=y;
>>
>
> It *is* the same.
>
>> I see here only one explicit operations:
>>
>> x.operator=(const moveable T&);
>>
>> It is not the same, because "std::move<T>" (operator<) can be used
>> separatedly from "move assignment" so (operator<) probably must return
>> intermediate _value_ of internal state. But explicit using of
>> "std::move<T>"
>> is overhead (especially in the case, when we no need internal value
>> because
>> it will be immediately reassigned to new object).
>>
>
> Why 'probably'?
Because most operators in C++ can return any value, and i do not see why
"operator<" must be an exception.
And are you agree, that "returning intermediate _value_ of internal state"
is overhead in comparison with direct move ctor/assignment or not?
> Why don't you read the proposal? In fact, it's a
> single operation: T's move assignment operator.
I read it many times but can not understand it because either semantics of
used terms contradicts to the same ordinary C++ terms or i even can not
imaging how a property of so simple thing as "moveable balue and reference"
can be implemented in the proposal even in theory.
Of course, i can copy examples from the proposal, but it is worse than bad.
--
Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new
---
[ 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 ]
Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Fri, 16 Mar 2007 12:45:57 CST Raw View
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 ]
Author: tasjaevan@gmail.com
Date: Sat, 17 Mar 2007 00:05:40 CST Raw View
On Mar 14, 5:48 pm, grizl...@yandex.ru ("Grizlyk") wrote:
>
> Tell me please, "r-value reference" is "moveable reference" or "moveable
> value"? There are great differences between "value" and "reference" data
> types in C++. Any "reference" is always address "sizeof(r-value
> reference)==sizeof(reference)". What "sizeof(T&&)" is? Consider _simplest_
> example with moveable:
>
An r-value reference is mostly identical to a regular (lvalue)
reference. It doesn't directly mean 'moveable', but it does enable
move semantics. I've translated your examples below (but real world
examples would be better than snippets of syntax).
> template<class T>
> void foo(T moveable& t)
> {
> t = 3;
> //here _no_ end of "t" life-time
>
> }
>
template <class T>
void foo(T&& t)
{
t = 3;
}
> template<class T>
> T moveable boo(const T moveable t)
> {
> //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)
{
T tmp(std::move(t));
tmp = 3;
return tmp;
}
The value return type is deliberate. This allows the return value
optimisation, which is more efficient than a move.
> template<class T>
> moveable T voo()
> {
> moveable T x;
> foo<T>(x);
> //here end of "x" life-time and reassignment of "x"
> x=boo<T>(x);
> //here end of "x" life-time
> return x;
>
> }
>
template <class T>
T voo()
{
T x;
foo<T>(std::move(x));
x = boo<T>(x); // no std::move required here, since boo returns by
value
return x;
}
>
> > Even with the current syntax, I think we have a challenge finding how
> > to teach && references, so that this seems natural.
>
> > The way I think of it is that && references are only relevant in
> > parameter lists, return types and casts (although std::move and
> > std::forward should be used instead of casts).
>
> What does "std::move" mean?
>
It simply turns the expression into an rvalue.
> T y;
> T x;
> x=std::move(y);
>
> I see here two explicit operations:
>
> x.operator=( from std::move<T>_return_value )
>
No, std::move only affects the rvalue-ness of the expression. It does
nothing by itself.
> Note, it is not the same as
>
> T y;
> T moveable x;
> x=y;
>
It *is* the same.
> I see here only one explicit operations:
>
> x.operator=(const moveable T&);
>
> It is not the same, because "std::move<T>" (operator<) can be used
> separatedly from "move assignment" so (operator<) probably must return
> intermediate _value_ of internal state. But explicit using of "std::move<T>"
> is overhead (especially in the case, when we no need internal value because
> it will be immediately reassigned to new object).
>
Why 'probably'? Why don't you read the proposal? In fact, it's a
single operation: T's move assignment operator.
James
---
[ 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 ]
Author: grizlyk1@yandex.ru ("Grizlyk")
Date: Sat, 17 Mar 2007 15:11:08 GMT Raw View
Howard Hinnant 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.
Assuming _there is_ difference between the human language and the proposal
syntax. I do not think that can exist "human C++ language" and "C++ language
of proposal syntax".
For example, I could propose new data C++ type "universe". Speking "C++
language of proposal syntax" the "universe" is only one data type, that must
exist in C++: char, int, double, user defined casses - all can be
represented by the "universe":
universe foo(universe u)
{
universe tmp(u);
return tmp;
}
We can goto further, remove even the "universe", and write like this:
foo(u)
{
tmp(u);
return tmp;
}
But there is difference between the human language and the proposal syntax.
> From your
> comments above I believe the correct syntax transformation would just be:
>
> template <class T>
> T boo(T t)
> { ...
You have changed
>> T moveable boo(const T moveable t)
into
> T boo(T t)
I suspect you think that "moveable" is the same as "non-const". This is one
of the "6 points of disagreement", the point has been quietly ignored by you
(the point remained without answer). No, in the message below you have
writeen a little about it.
Really, there are huge difference between:
T boo(T t)
and
T boo(const T t)
and
T boo(T moveable t)
and
T boo(const moveable T t)
This is really _4_ different data types of parameter, named "t". You are
agree or not?
Also between
T foo([const] T t)
and
T boo([const] moveable T t)
the difference is "what constructor (copy or move) will be implicitly used
to make t":
T src;
foo(src);
//here "copy constructor" will make "t" from "src"
//T(const T&);
boo(src);
//here "move constructor" will make "t" from "src"
//T(const moveable T&:(ctor;dtor));
>
> You are correct that an rvalue reference is just like our existing
> reference today in that it is just a pointer underneath.
Either "r-value" reference is only "moveable reference" or is only "moveable
value" - both case is not enough, because we need "moveable reference and
value" simultaneously.
And unfortunately, the current way of implementation of "move semantics with
the help of r-value reference", that has been selected, even in theory can
not be upgradeable to make complete support of the "move semantics", that
can be easy done in real compilers.
Also it is a big question: do we need to call "moveable" as "rvalue"? I do
not think so.
>
>> > {
>> > 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.
What does "RVO" mean - r-value what?
ref>Copy constructor elision (NRVO) almost fixes this, but not quite
Assuming RVO is "copy constructor elision". (Below you have declared "RVO
(return value optimization)").
> 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.
Are you really trying to find all possible cases where "implicit move
constructor" can be applied and then hard include the cases into language
instead of to give to user general tools to express what he wants?
Looking to expression
T boo()
{
T tmp(3);
return tmp;
}
user must guess, that T will be maked by "move constructor" (if move ctor
declared). But what user must do if he want to use "copy constructor" (in
spite of move ctor can be declared), as the C++ declaration normally
requires?
If we have no body (note it is onle of the 6 point of disagreement, quietly
ignored by your)
T boo();
can you detect, does "boo" return value will be created by "T copy ctor" or
by "T move ctor"?
Do you see that there is no tools to express correct and clear code, if
"moveable" will be based on the fact, that "Copy constructor can be elided"?
It is the same as if we invent hard included into language "const" data
type, because some C++ libraries has been written without "const", for
example like this:
inline T boo(T t)
{
T tmp(t);
return tmp;
}
here "t" will be implicitly const in C++, because correct code must assume
"t" is const, in order to not allocate new memory for "t", compiler will be
able to optimize "t", using "t" as alias or as reference of source variable.
Do you like the kind of "const"? The "r-value reference" is the same,
because it is impossible to express new data type as "little refinement of
old data type".
>
> 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
No, we need to be able to declare move semantics _explicitly_ (and use the
semanics without std::move()). The set of rules is interesting as example of
implementation of rules of interaction of "copyable and moveable" data
types, but the rules can not be used as definition of moveable declaration.
Definition of "moveable declaration" and data optimization ("RVO") must be
separated!
By the way, the rules can be wrong for moveable data type included as
ordinary C++ data type, because we must not prefer "move" befor "copy", no
reasons to do it and "elide" is not the same as "move".
>
> 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
C++ already have syntax idiom to declare data types without
"make_unique_ptr", and supporting the ordinary C++ syntax idiom is better
for any new regular stuff in comparison with irregular user defined one
unique_ptr<int> p1;
unique_ptr<int> p2 = p1; // compile time error
moveable unique_ptr<int> p3 = p1; // 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.
Well, return value optimization is one of the possible optimization of data
and must be separated from moveable data type proposal, at least to allow to
develop the stuffs independently!
> 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.
I am afraid we have some serious, base disagreements. I suspect, i have no
enough C++ knowledge to generate own proposal of C++ moveable, so i want to
convince you to change your proposal and your mind into correct way, into
way based on requirements that has been detected by me (and probably by
other users) in practical situations, not only from theoretical refinement
of RVO, ( i think theoretical because i have not seen nany users, operaiting
with rvalue/lvalue data types in their programs before).
The detected sources of moveable data type and detalied explanation of them
can be found on my page http://grizlyk1.narod.ru/cpp_new article #11-#15,
and among them
- moveable is ordinaty data type, unrelated to r-value term
- non-const is not the same as moveable
- compile time attributes is way to make moveable usage safe
- and so on
It is possible, that "r-value reference" with syntax "T&&", being subset of
ordinary moveable data type (but with special "r-value reference" rules),
can co-exist with ordinary moveable data type with syntax "moveable T&" (and
ordinary C++ rules), that can give to users more freedom to select its
design.
But if it is impossible to make C++ as huge collection of different moveable
behaviours, then regular ordinary moveable data type with syntax "moveable
T&" (and ordinary C++ rules) must be selected agains most other possible
representations.
>> 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();
1. The expression "a =< b;" in my proposal is two operators
a.operator=( b.operator<() );
not single
a.operator=<(b);
The expression "a =< b;" often used as one of the way of data type local
override or for iterator-like access instead of "operator*()", because
iterator is kind of pointer. Normally we must write like this
moveable T a;
a = b;
//here move ctor used according to
//"a" declaration
2. Operator move (<) is "unary operator", similarly to "asterisk" (*), so
correct definition of "operator<"
any_type T::operator<()dtor;
or
friend any_type T::operator< (T const moveable&:(ctor;dtor));
>>
>> 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.
Maybe, for "prefix unary operator move" can be used any: "<", "<-" and so
on. "<" is most short one. Sequence "<class A, class B<A>>" of template can
be confused with ">>" operator.
I think postfix binary "operator=<" is not needed for moveable, because move
constructor used according to moveable declaration of target data type.
We have a requirement of local explicit data type override, but
static_cast<> maybe can be used. Can we allow cast to copyable from
moveable? Do we need special moveable_cast<>?
The moveable_cast<> is similar to const_cast<> for "const" data type,
sometimes i think the names could be more clear as unconst_cast<> and
copyable_cast<> (by name of destination type, not source).
moveable T a;
//cast to copyable reference: copy ctor will be used
static_cast<T&>(a) = b;
moveable_cast<T&>(a) = b;
>>
>> 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);
We need operators "move" and "swap" just because last is basical data
operation, exist in most CPU as high perfomans single opcode for POD data,
and first is basical operation under moveable data type (as assignment under
copyable data type). The absence of the operators in C++ can not be
explained by any rational rationale, can be only by "i do not want".
Do you want to write for copyable
a.std::assign( std::asteriks(b) );
insead of
a=*b;
>
> Some major points:
>
> * Compile time detection of double-move is not realistic.
And you already have made counting of the difficulties? The compile time
"detection of double-move" is not more difficult than "assignment to const"
or "variable is never used" compile time detections.
> It simply
> can not be done reliably enough in real world use cases.
The your opinion is contradicts to my concrete provements and is not based
on any concrete facts of "real world use cases".
> The original
> proposal recognizes this fact,
Can i read about details of the process of recognizing more?
> 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
I think we need refuse from "const" also, because it makes compiler
difficult (becasue let's compiler give back all its forces to compile
templates, instead of "assignment to const" detection), because programmers
can more easily audit their code for assignment to const:
//non const
int b;
//const
int a=std::assing_to_const(b);
.
a=std::assing_to_const(b); // this is greppable
Nice?
I know, Stroustrup once wrote something like "C++ modifications can be
implemented by library", but the sentence can not be used totaly everywhere,
especially if the way will contradicts with regular C++ rules. There are
differneces between "moveable data type appearance" and "printf
replacement".
> * 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.
Who does argue? We need use correct syntax:
auto_ptr<A> p1;
moveable auto_ptr<A> p2 = p1;
now OK
> * Generic algorithms need to work with types that are:
>
> - only have copy constructors
> - have both move and copy constructors
I do not argue, i can repeat from my page:
Appearence of new ordinary data type (owning rights of data type) turns the
situation from boolean state: "non-copyable/copyable" into more complex
'combinatoric' state: "non-copyable/moveble/copyable" with defined
relationship between bolean state: "moveble/copyable".
But "moveble" is not guilt, it is becasue of nature of "high perfomans
transfer of dynamic memory over auto memory boundaries combined with
automatic free of the memory on the auto memory boundaries".
> 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.
Let's people make the selection, maybe they have own generic algorithms
perfectly working for these cases? We must not reject any usefull general
design stuffs from language just because obsolete implementation of stdlib
can not work with them without modifications or can not use it completely.
The stdlib is not a Bible, so we must not design language in order to be
compartible with concrete implementation of any library. Correct user code,
working with interfaces of any library will not see any changes in library
implementation.
By the way, stdlib will continue to work without any modification on "C++
with moveable support", because moveable is orthogonal property, of course,
moveable data type can not be used just because stdlib does not support
them.
> 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.
Again, i do not argue, if vector<> can work with unique_ptr<int>, internals
of vector<> must be declared as using of moveable only:
template<class T>
class vector<T>
{
moveable T <memory>* data;
.
};
I am thinking - do we need to declare any template as strict copyable or
moveable:
template<copyable class T>
class vector<T>;
in order to detect error at the the point of declaration instead of
returning internals of hidden templated implementation:
template<class T>
void foo()
{
moveable T t;
vector<T> v;
error T must be copyable according to declaration
template<> class vector;
instead of messages that:
test.cpp: 20: \
instantiated from:\
lin/sd/sds/ds/ds/ds/dsd/s.cc: 303\
instantiated from:\
lin/sd/sds/ds/ds/ds/ds/f.cc: 30\
instantiated from:\
lin/sd/werwer.cc: 298\
instantiated from:\
lin/sd/sds/ds/ds/ds/ds/ds/dsd/s.cc: 30304\
: erorr: asdas:ASDASD:ASDa:ASdasd:ASda:Asda:Asd:data\
<asdas:ASDASD:ASDa:ASdasd:ASda:Asda,\
asdas:ASDASD:ASDa:ASdasd:ASda:Asda,\
asdas:ASDASD:ASDa:ASdasd:ASda:Asda\
>& \
is private in the context
}
I can repeat, in my page the question of copyable and moveable interaction
placed in section "problems", but (unlike to moveable data type definitions
having no any problems) the problems of interacltion here _only_ because of
i have no any information to make correct definition of the rules of
interaction, because the rules have _random rationale_. We can declare any
rule, as we need by concrete requirements of interaction.
Anyway, you are trying to consider very complex examples of interaction of
copyable and moveable, and it seems to me, the way of consideration is
hiding the essence of the real problems of moveable data type by
difficulties of the examples of interaction as exmples itself.
Try consider my proposal of "regular moveable data type" step by step, from
#11 to #15, you will see, there are no any limitations for copyable and
moveable interaction.
>
> * I think it is unwise to move from const-qualified types. A move is
> allowed to change the source.
Returning to question of "const moveable". I have posted tons of examples
where difference between const and moveable has been shown. The followin
explanation has been taken from my page:
http://grizlyk1.narod.ru/cpp_new/#12
[quote]
NOTE: "Non-const" is not the same as "moveable".
It is very important thing to see the differences between "non-const" and
"moveable". And comparing operations "move" and "swap" we can easy to find
the differences.
I think some people are trying to declare moveable (auto_ptr for exmple) as
non-const in hope to warn user, that the moveable has unexpected, hidden
assignment to its internal state, after operation "move" (the "move"
implemented as overloading operation "copy") has executed.
- It is easy to see, that the warning is similar to refusing from static
type checking with the help of "void" speaking "we garantee nothing".
- Also it is easy to see, that non-const can not protect us from logically
wrong "operator move" has been applied twice to the non-const object (double
move). We can say, that move semantic required from C++ "once" support
rather than "non-const" support, it is really different things.
- So if assuming, that "operator move" (address extraction from auto_ptr)
can occur only once for the concrete moveable object (that must be garanteed
by programmer because C++ still can not do it), the moveable (auto_ptr) can
be const. The "once" is independent from "const".
- Also the moveable (auto_ptr) must be const if we want to disable explicit
assignment to the moveable (auto_ptr). Remove constness in order to make
only "move" is wrong idea and does not require by move semantic.
Non-const can be used for any purpose, but due to non-const can not protect
moveable from "double move", const must be used for standard purpose -
protect from explicit changes of external state of moveable (from assignment
for example). Consider the differences:
1.
template<T>
void swap_1(T& lhs, T& rhs)
{
const T dummy ( <lhs );
//ok
//here "const T" protect us from wrong assignment to temporary
dummy= <rhs; //compile time error
lhs= <rhs;
rhs= <dummy;
//error
//here compiler must generate error
//independent from constness of dummy
//because "double move" is "once" violation
<dummy;
}
2.
template<T>
void swap_2(T& lhs, T& rhs)
{
T dummy ( <lhs );
//error
//here compiler must generate error
//but "non-const T" can not protect us from wrong assignment to temporary
dummy= <rhs; //ok
lhs= <rhs;
rhs= <dummy;
//error
//here compiler must generate error
//independent from constness of dummy
//because "double move" is "once" violation
<dummy;
}
And the fact that "const dummy" does not strictly required for function
"swap", is not speaking that all other functions does not strictly require
const movable.
In opposite to "operator move", "operator swap" really require non-const to
its argumets, because (unlike to "move") we are going to use the swap
arguments after "operator swap" has been executed.
[/quote]
> If you declare something const, then you
> are saying you don't want it changed.
On your page:
ref> Moving from const objects (even rvalues) must be prohibited.
ref> It is very difficult to distinguish between a const and an rvalue
ref> in the current language (not impossible ... auto_ptr pulls it off).
The sentence "in the current language" - I think you have made a big mistake
trying to adapt term "rvalue" to "moveable" and looking on "moveable" from
"rvalue" side instead of side of ordinary data type. The "moveable" type is
very different from "copyable" as "const" from "non-cost".
The heroic attempt to "make moveable from void, doing nothing" will be only
new wrong point of C++, because i hope you know placement of free cheese.
PS:
I thanks you and other that you have a time and forces to answer.
But really (in spite of the your current answer is more closely to "answer
by essence") due to the technic of "ignoring all found unsuitable questions"
we are nearly month jumping on the same point where we was in february.
If it is not deliberate accidents, then the situation must be improved
maybe? At least we are spearing about C++ property, that can not give us
personally any profits or losses.
If it is deliberate strategy, in fact it means "r-value and other proposals
is not disputable" and i only can regret about the accident as for all other
known error points of C++, that can not give user abilities to do what he
wants and C++ can do.
I think (and have written many arguments), if even allow the "r-value
regerence" will exist in C++, the "r-value regerence" can not be used as
"moveable data type replacement", so we need "correct copyable and moveable
data type definitions" and "compile time attributes" to safe work with
"moveable data type".
--
Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new
---
[ 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 ]
Author: grizlyk1@yandex.ru ("Grizlyk")
Date: Wed, 14 Mar 2007 17:48:05 GMT Raw View
tasjaevan@gmail.com wrote:
>>
>> 'swap(rvalue C &other)' seems more intuitive to me.
>>
>
> For me, there is a big problem with an 'rvalue' keyword, at least with
> the exact functionality provided by the rvalue reference proposal.
>
> void f(int rvalue& t)
> {
> t = 3;
> }
>
> What is the type of t inside the function? It's an lvalue of type 'int
> rvalue&'. The rvalue keyword is entirely misleading.
I agree, "rvalue" keyword is a big problem. The best solution is "moveable"
keyword.
I think the appearence of "moveable" keyword is easy to see if to try to
extend the "r-value reference" definition for some other practical
applications, that have not been taken into account by original "r-value
reference" definition. In other words the "r-value reference" definition is
not only subset of "moveable", but one with many unsuitable limitations.
void f(int moveable& t)
{
t = 3;
}
Now all OK. It's an lvalue of type 'int moveable&'. The "moveable" keyword
is one of the excellent one.
Tell me please, "r-value reference" is "moveable reference" or "moveable
value"? There are great differences between "value" and "reference" data
types in C++. Any "reference" is always address "sizeof(r-value
reference)==sizeof(reference)". What "sizeof(T&&)" is? Consider _simplest_
example with moveable:
template<class T>
void foo(T moveable& t)
{
t = 3;
//here _no_ end of "t" life-time
}
template<class T>
T moveable boo(const T moveable t)
{
//here end of "t" life-time
T moveable tmp(t);
tmp = 3;
//here end of "tmp" life-time
return tmp;
}
template<class T>
moveable T voo()
{
moveable T x;
foo<T>(x);
//here end of "x" life-time and reassignment of "x"
x=boo<T>(x);
//here end of "x" life-time
return x;
}
Can you express the same with "r-value reference"? Write it just here.
>
> Even with the current syntax, I think we have a challenge finding how
> to teach && references, so that this seems natural.
>
> The way I think of it is that && references are only relevant in
> parameter lists, return types and casts (although std::move and
> std::forward should be used instead of casts).
What does "std::move" mean?
T y;
T x;
x=std::move(y);
I see here two explicit operations:
x.operator=( from std::move<T>_return_value )
Note, it is not the same as
T y;
T moveable x;
x=y;
I see here only one explicit operations:
x.operator=(const moveable T&);
It is not the same, because "std::move<T>" (operator<) can be used
separatedly from "move assignment" so (operator<) probably must return
intermediate _value_ of internal state. But explicit using of "std::move<T>"
is overhead (especially in the case, when we no need internal value because
it will be immediately reassigned to new object).
--
Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new
---
[ 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 ]
Author: krzikalla@gmx.de (Olaf Krzikalla)
Date: Thu, 15 Mar 2007 14:52:14 GMT Raw View
Hi,
Howard Hinnant wrote:
> You just labeled std::sort as exotic. :-)
Fortunately for me I wrote 'mostly' :-)
However besides the various sort algorithms I don't see anything widely
used:
> reverse
> random_shuffle
> partition
> next_permutation
> prev_permutation
OTOH maybe I'm just working in the wrong application domain.
>>There is only one remaining question related to pt.1 a page above: is it
>>possible to break code due to a compiler generated move-op, if a class
>>consists of std lib classes and has no user-defined copy-op?
>>I won't think so but I can't proof it either.
>
>
> <nod> Just stumbled over one. I've been working the threading area
> lately so that's on my mind.
>
> Consider:
>
> class thread_pool
> {
> std::vector<thread> threads_;
> ...
> public:
> ...
> };
>
> Then intent of the author is that thread_pool is neither movable nor
> copyable. It must communicate with remotely controlled data structures
> which point back to this thread_pool. Now one could make such a
> thread_pool movable, by alerting those remote structures of the move.
> But this author has chosen not to.
>
> By the current rvalue-ref language rules in the working draft, the above
> (admittedly sketchy) prototype is sufficient to prohibit moving and
> copying of thread_pool. thread is a move-only handle. And that makes
> std::vector<thread> a move-only object (copy constructor is ill formed).
>
> Now if we implicitly auto-generate move members for thread_pool, then
> those members will access the undesired move members of
> std::vector<thread>. thread_pool becomes movable, but with the improper
> logic. The remote structures remain unaware that their reference back
> to the thread_pool is now dangling. We've turned what thread_pool's
> author intended to be a compile time error into a run time error.
But the example isn't suitable for our discussion. It doesn't silently
break just because the thread_pool user switches to C++0x and a new
thread library. The user has to add or change code, which accidently
moves a thread_pool.
In addition you should note, that the same point could be made against
compiler-generated copy-ctors: If the thread class (or something
similiar) becomes copyable for some reason, thread_pool implicitely
becomes so too, even if it's not intended.
I consider move-ops and copy-ops being something like twins, since their
intents are very similiar. That is, they should be handled as similiar
as possible. However since the copy-ops are the first-borns (and thats
being the only reason!) they sometimes have to overrule their little
brothers (see rule 2 in my previous post). I'm afraid that if there are
no options to generate a move-op by the compiler, their usage becomes
really tedious.
E.g., sometimes I have a bigger class with a lot of properties and a
little part, which needs a copy-ctor. I this case I can put the 'little
part' in a sub-class with a very small user-defined copy-ctor. The
compiler does the rest for me in the 'bigger class'. And I don't have to
worry if someone adds a new property to the class. And - btw - that's
exactly the type of class, where a move-ctor could be very useful.
Best regards
Olaf Krzikalla
---
[ 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 ]
Author: tasjaevan@gmail.com
Date: Thu, 15 Mar 2007 13:47:16 CST Raw View
On Mar 14, 5:48 pm, grizl...@yandex.ru ("Grizlyk") wrote:
>
> Tell me please, "r-value reference" is "moveable reference" or "moveable
> value"? There are great differences between "value" and "reference" data
> types in C++. Any "reference" is always address "sizeof(r-value
> reference)==sizeof(reference)". What "sizeof(T&&)" is? Consider _simplest_
> example with moveable:
>
An r-value reference is mostly identical to a regular (lvalue)
reference. It doesn't directly mean 'moveable', but it does enable
move semantics. I've translated your examples below (but real world
examples would be better than snippets of syntax).
> template<class T>
> void foo(T moveable& t)
> {
> t = 3;
> //here _no_ end of "t" life-time
>
> }
>
template <class T>
void foo(T&& t)
{
t = 3;
}
> template<class T>
> T moveable boo(const T moveable t)
> {
> //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)
{
T tmp(std::move(t));
tmp = 3;
return tmp;
}
The value return type is deliberate. This allows the return value
optimisation, which is more efficient than a move.
> template<class T>
> moveable T voo()
> {
> moveable T x;
> foo<T>(x);
> //here end of "x" life-time and reassignment of "x"
> x=boo<T>(x);
> //here end of "x" life-time
> return x;
>
> }
>
template <class T>
T voo()
{
T x;
foo<T>(std::move(x));
x = boo<T>(x); // no std::move required here, since boo returns by
value
return x;
}
>
> > Even with the current syntax, I think we have a challenge finding how
> > to teach && references, so that this seems natural.
>
> > The way I think of it is that && references are only relevant in
> > parameter lists, return types and casts (although std::move and
> > std::forward should be used instead of casts).
>
> What does "std::move" mean?
>
It simply turns the expression into an rvalue.
> T y;
> T x;
> x=std::move(y);
>
> I see here two explicit operations:
>
> x.operator=( from std::move<T>_return_value )
>
No, std::move only affects the rvalue-ness of the expression. It does
nothing by itself.
> Note, it is not the same as
>
> T y;
> T moveable x;
> x=y;
>
It *is* the same.
> I see here only one explicit operations:
>
> x.operator=(const moveable T&);
>
> It is not the same, because "std::move<T>" (operator<) can be used
> separatedly from "move assignment" so (operator<) probably must return
> intermediate _value_ of internal state. But explicit using of "std::move<T>"
> is overhead (especially in the case, when we no need internal value because
> it will be immediately reassigned to new object).
>
Why 'probably'? Why don't you read the proposal? In fact, it's a
single operation: T's move assignment operator.
James
---
[ 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 ]
Author: howard.hinnant@gmail.com (Howard Hinnant)
Date: Thu, 15 Mar 2007 19:49:26 GMT Raw View
In article <etbgro$o59$1@news.albasani.net>,
krzikalla@gmx.de (Olaf Krzikalla) wrote:
> E.g., sometimes I have a bigger class with a lot of properties and a
> little part, which needs a copy-ctor. I this case I can put the 'little
> part' in a sub-class with a very small user-defined copy-ctor. The
> compiler does the rest for me in the 'bigger class'. And I don't have to
> worry if someone adds a new property to the class. And - btw - that's
> exactly the type of class, where a move-ctor could be very useful.
I just today read:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2210.html
Although the proposal doesn't mention move members, I would support:
struct A
{
...
A(A&&) = default;
A& operator=(A&&) = default;
void swap(A&&) = default;
};
void swap(A&&,A&&) = default;
This avoids most of the tedium you speak of for classes with many data
members.
-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 ]
Author: krzikalla@gmx.de (Olaf Krzikalla)
Date: Wed, 7 Mar 2007 14:51:35 GMT Raw View
Hi,
Howard Hinnant wrote:
> Fwiw:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html
What strikes me most is the omission of a proposal (or at least a
discussion) for compiler-generated move-ctors and assignment operators.
I'm aware of the fact, that this isn't as easy as defining rules for
compiler-generated copy-ctors simply because there is no really move
semantic for fundamental types. I see two possible approaches for
fundamental types:
T y = x; // simple copy
and
T y = x;
x = 0; // could be T(), but 0 emphasizes, that T is a fundamental type
While the second one would catch more cases by default I prefer the
first one, since its faster and cleaner. Of course this would silently
break existing code. However if someone makes the transition to C++09 he
must be aware of language changes anyway. And one change would be, that
the rule of the big three becomes the rule of the big five.
Whatever, I often have things like this:
struct tHelper
{
std::string s1;
std::string s2;
std::string s3;
};
and current C++ generates the remaining things as I need them (in its
current bounds of course). Making move-ctors and assignment operators
not compiler generated would make them only narrow useful.
Best regards
Olaf Krzikalla
---
[ 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 ]
Author: "=?iso-8859-1?q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Wed, 7 Mar 2007 08:50:45 CST Raw View
On Mar 7, 5:10 am, "W Karas" <wka...@yahoo.com> wrote:
> On Mar 6, 12:40 pm, howard.hinn...@gmail.com (Howard Hinnant) wrote:> In article <1173184878.379660.46...@h3g2000cwc.googlegroups.com>,
> > "W Karas" <wka...@yahoo.com> wrote:
> .
>
> > > 'swap(rvalue C &other)' seems more intuitive to me.
>
> > <shrug>The currently proposed syntax was chosen so as to avoid the need
> > to introduce new keywords. Syntax such as you suggest was considered.
>
> .
>
> Seems like there's lots of new kewords in C++09 anyway. But, if
> rvalue types are otherwise superior to rvalue references, I would
> vote for introducing the weird notion of a scoped keyword:
>
> swap(std::rvalue C &other)
>
> if making rvalue a "normal" keyword is unacceptable.
There exists no concept of a "scoped" keyword in C++. If
you would just introduce this concept, this would influence large
parts of the language and basically every compiler vendor would
have to reimplement it's most interior and up to that moment
long tested "kernel part" - this is most probably inacceptable
compared to the benefits (at least on the first sight).
Besides the disadvantages characterized above something
like your proposed entity std::rvalue does not fit into the
language. From the way you propose to use it, most would
expect it to be a type, not a specifier. But std::rvalue C makes
no sense at all. Or can I declare something like
std::rvalue mydatum;
? In short, this leads to many asymmetries compared to the
existing language.
Yes, there exists advantages of an alternative idea, that is the
idea of a context-related keyword (most notably the fact that it
makes it easier to introduce new context-related keywords
without fear of breaking code), but to the same high initial costs,
because it would invalidate current C++ parsing the same way
as your "scoped" keyword ansatz.
Greetings from Bremen,
Daniel Kr gler
---
[ 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 ]
Author: tasjaevan@gmail.com
Date: Wed, 7 Mar 2007 11:37:05 CST Raw View
On Mar 6, 2:36 pm, "W Karas" <wka...@yahoo.com> wrote:
>
> 'swap(rvalue C &other)' seems more intuitive to me.
>
For me, there is a big problem with an 'rvalue' keyword, at least with
the exact functionality provided by the rvalue reference proposal.
void f(int rvalue& t)
{
t = 3;
}
What is the type of t inside the function? It's an lvalue of type 'int
rvalue&'. The rvalue keyword is entirely misleading.
Even with the current syntax, I think we have a challenge finding how
to teach && references, so that this seems natural.
The way I think of it is that && references are only relevant in
parameter lists, return types and casts (although std::move and
std::forward should be used instead of casts).
James
---
[ 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 ]
Author: howard.hinnant@gmail.com (Howard Hinnant)
Date: Wed, 7 Mar 2007 17:56:26 GMT Raw View
In article <esm4sb$pk2$1@news.albasani.net>,
krzikalla@gmx.de (Olaf Krzikalla) wrote:
> What strikes me most is the omission of a proposal (or at least a
> discussion) for compiler-generated move-ctors and assignment operators.
You're not alone in noting that. It has been proposed (informally, not
formally) several times... enough times that I would consider it a faq,
and have attempted to answer this particular question here:
http://home.twcny.rr.com/hinnant/cpp_extensions/rvalue_ref_rationale.html
In a nutshell, one of the design goals has been that working code in
C++03 does not break when simply recompiled under C++0X. The above
document explores code that works today, but breaks with implicitly
generated move members.
There was a proposal to add syntax for explicitly requesting
compiler-generated special members:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1717.pdf
And I would have loved to have seen this applied to the move constructor
and move assignment as well. However at this time it appears that this
proposal will not be applied to C++0X.
-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 ]
Author: "W Karas" <wkaras@yahoo.com>
Date: Fri, 9 Mar 2007 09:01:43 CST Raw View
On Mar 7, 9:50 am, "Daniel Kr gler" <daniel.krueg...@googlemail.com>
wrote:
> On Mar 7, 5:10 am, "W Karas" <wka...@yahoo.com> wrote:
..
> > I would
> > vote for introducing the weird notion of a scoped keyword:
>
> > swap(std::rvalue C &other)
>
> > if making rvalue a "normal" keyword is unacceptable.
>
> There exists no concept of a "scoped" keyword in C++. If
> you would just introduce this concept, this would influence large
> parts of the language and basically every compiler vendor would
> have to reimplement it's most interior and up to that moment
> long tested "kernel part" - this is most probably inacceptable
> compared to the benefits (at least on the first sight).
Yes I guess we shouldn't break with the long tradition
of defining the C syntax in a way that's easy to parse. :o)
You're right, I just threw out std::rvalue as a less ugly
version of _rvalue .
> Besides the disadvantages characterized above something
> like your proposed entity std::rvalue does not fit into the
> language. From the way you propose to use it, most would
> expect it to be a type, not a specifier. But std::rvalue C makes
> no sense at all. Or can I declare something like
>
> std::rvalue mydatum;
>
> ? In short, this leads to many asymmetries compared to the
> existing language.
..
Since _rvalue is a modifier, you'd need a type:
_rvalue X mydatum;
But maybe a different keyword would be more descriptive:
_terminal X mydatum;
It would not be the first C++ feature that had some
legal-but-pointless uses, and some marginally
useful uses (along with the highly useful
uses). The point is to be able to create
funtion overloads that have write access
to certain parameters, and where the
functions know it is ok to take the resources
of the said parameter object.
---
[ 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 ]
Author: krzikalla@gmx.de (Olaf Krzikalla)
Date: Mon, 12 Mar 2007 15:47:26 GMT Raw View
Hi,
Howard Hinnant wrote:
> You're not alone in noting that. It has been proposed (informally, not
> formally) several times... enough times that I would consider it a faq,
> and have attempted to answer this particular question here:
>
> http://home.twcny.rr.com/hinnant/cpp_extensions/rvalue_ref_rationale.html
>
> In a nutshell, one of the design goals has been that working code in
> C++03 does not break when simply recompiled under C++0X.
Sad to hear that. But we better don't discuss that further.
> The above
> document explores code that works today, but breaks with implicitly
> generated move members.
However, if move members are never generated implicitly they become
second class citizens of the language. And you can't expect the average
programmer start writing move ctors (as he seldom is enforced to write
copy ctors) which in turn renders all the effort made in the std lib
rather useless.
Is there any reasonable class with compiler-generated copy ctor, which
would break with a compiler-generated move ctor? If not, then maybe
thats the way to go: if a class has either a user-declared copy ctor or
a user-declared assingment operator, then there are no
compiler-generated move members. If neither copy ctor nor assingment
operator are user-declared, move members are generated automatically by
the compiler.
Best regards
Olaf Krzikalla
---
[ 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 ]
Author: howard.hinnant@gmail.com (Howard Hinnant)
Date: Mon, 12 Mar 2007 18:22:19 GMT Raw View
In article <et3fat$i43$1@news.albasani.net>,
krzikalla@gmx.de (Olaf Krzikalla) wrote:
> However, if move members are never generated implicitly they become
> second class citizens of the language. And you can't expect the average
> programmer start writing move ctors (as he seldom is enforced to write
> copy ctors) which in turn renders all the effort made in the std lib
> rather useless.
Actually I expect average programmers to generate their own swap
functions today.
struct tHelper
{
std::string s1;
std::string s2;
std::string s3;
};
This is going to swap with horrible performance, and perhaps even more
importantly, the swap can throw.
And no, I don't believe swap is a second class citizen in the language.
And yes, I would be nervous about adding an implicitly generated swap to
user-defined types.
> Is there any reasonable class with compiler-generated copy ctor, which
> would break with a compiler-generated move ctor? If not, then maybe
> thats the way to go: if a class has either a user-declared copy ctor or
> a user-declared assingment operator, then there are no
> compiler-generated move members. If neither copy ctor nor assingment
> operator are user-declared, move members are generated automatically by
> the compiler.
I believe this would be susceptible to the "fragile base class" problem.
Consider a library author who writes in C++03:
class Base
{
public:
Base(const Base&);
...
};
He has clients (other authors) which derive from (or contain) Base:
class Client
: Base
{
...
};
And lets assume that the copy semantics of Base are suitable for Client,
so there is no explicit Client(const Client&).
Now C++0x comes along. Base wants to add a move constructor. Can he do
so and be assured we won't break existing Clients?
The move semantics for Base may not be suitable for the Client. It
might do something that seems perfectly reasonable for Base, but
completely unreasonable for Client, even though the default copy
semantics was appropriate (it is difficult to know all the ways clients
use your code). Perhaps it is sensible for Base(Base&&) to tell
referencing entities to destruct themselves, and perhaps that would be
completely unsuitable for Client. And yet both Base and Client are
happy with resource duplication when it comes to copy semantics (just an
example).
If Client has to explicitly request to use Base's move constructor, then
you have a reasonable assurance that Client has read Base's
documentation and knows what he's doing. However if vector<Client> just
suddenly starts calling Base(Base&&) upon a simple recompile of Client's
code in C++0X, I believe we have the possibility of breakage.
I would rather tell people: Go ahead and add move constructors to your
classes. Don't worry, you will not silently break your client's code
(you may also not help your client's code unless you communicate your
changes to your clients).
Move semantics has been designed as strictly an opt-in system. Not an
opt-out system. Yes, you can call me conservative. I'll take it as a
compliment. :-)
Thanks for the suggestion though. I think this would be a good one to
add to my rationale document. And perhaps if I get time, I'll even
flesh out a concrete Base/Client example.
-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 ]
Author: krzikalla@gmx.de (Olaf Krzikalla)
Date: Tue, 13 Mar 2007 13:48:55 GMT Raw View
Hi,
Howard Hinnant wrote:
> Actually I expect average programmers to generate their own swap
> functions today.
Hmm, I've never seen one so far (including me).
> And no, I don't believe swap is a second class citizen in the language.
Here I disagree. Maybe I've never seen a user-generated swap because
it's rather useless. Only very few (mostly rather exotic) std algorithms
are defined in terms of std::swap. Implementations of e.g. remove or
std::vector::erase use assignment operators instead of swap.
> And yes, I would be nervous about adding an implicitly generated swap to
> user-defined types.
Me too. To a certain degree swap currently acts as a workaround for the
missing built-in move-ops (move ctor and move assignment). If we'd have
these no one cares about swap anymore (I exaggerated, I know).
> I believe this would be susceptible to the "fragile base class" problem.
> Consider a library author who writes in C++03:
>
> class Base
> {
> public:
> Base(const Base&);
> ...
> };
>
> He has clients (other authors) which derive from (or contain) Base:
>
> class Client
> : Base
> {
> ...
> };
>
> And lets assume that the copy semantics of Base are suitable for Client,
> so there is no explicit Client(const Client&).
>
> Now C++0x comes along. Base wants to add a move constructor. Can he do
> so and be assured we won't break existing Clients?
No, of course not. But the question is: should he be assured? IMHO not.
We are talking about two subsequent transitions:
pt.1. Move from C++03 to C++0x (including the std lib). This wouldn't
break any client code (but see the last sentences of this posting).
pt.2. Now move the used client library to the C++0x version (there must
be a new C++0x-conformant library version, if Base has a move ctor).
This may break existing code. But it's always a sensible process to move
from one library version to another.
> Move semantics has been designed as strictly an opt-in system. Not an
> opt-out system. Yes, you can call me conservative. I'll take it as a
> compliment. :-)
Don't be offended but regarding the example above you aren't
conservative enough ;-)
Consider the following C++03 code:
void foo()
{
std::vector<Base> someBase;
someBase.push_back(Base());
someBase.push_back(Base());
someBase.push_back(Base());
//aso.
}
Now the library author adds a move ctor to Base in the C++0x version. If
either the move ctor or the copy ctor (or both) have a side effect then
the behavior of foo silently changes (i.e. breaks) in C++0x after a
library update - even without a compiler generated move ctor.
Hence even if the "fragile base class" problem may be used to
demonstrate how to break code in C++0x it can't be used as a
counter-argument for compiler generated move-ops IMHO. Thus we should
not care about pt.2!
Actually we could go with three rules:
r.1. A compiler generated move-op of a class consists of the (compiler
generated or user-defined) move-ops of the (base) members of that class.
r.2. If a class definition has a user-declared copy-op, the appropriate
move-op can't be compiler generated.
r.3. If the compiler can't generate a move-op due to rule 1 & 2 and
there is no user-declared move-op, the class has no move-op.
The first rule is trivial and well known. However it is needed to point
out that a compiler generated move-op is never a mixture of copy-ops and
move-ops. The second rule is the surprising one. But it makes move-ops
the claimed opt-in. The third rule is simple again. I guess it is used
in the current proposal too: the compiler falls back to a copy-op, if a
move-op is not available.
There is only one remaining question related to pt.1 a page above: is it
possible to break code due to a compiler generated move-op, if a class
consists of std lib classes and has no user-defined copy-op?
I won't think so but I can't proof it either.
Best regards
Olaf Krzikalla
---
[ 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 ]
Author: howard.hinnant@gmail.com (Howard Hinnant)
Date: Tue, 13 Mar 2007 17:10:25 GMT Raw View
In article <et643c$4ea$1@news.albasani.net>,
krzikalla@gmx.de (Olaf Krzikalla) wrote:
> Here I disagree. Maybe I've never seen a user-generated swap because
> it's rather useless. Only very few (mostly rather exotic) std algorithms
> are defined in terms of std::swap. Implementations of e.g. remove or
> std::vector::erase use assignment operators instead of swap.
>
> > And yes, I would be nervous about adding an implicitly generated swap to
> > user-defined types.
> Me too. To a certain degree swap currently acts as a workaround for the
> missing built-in move-ops (move ctor and move assignment). If we'd have
> these no one cares about swap anymore (I exaggerated, I know).
<nod> :-) See
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1771.html and
search for "Summary of algorithm requirements" for a concise list of
what functions in <algorithm> will use swap, move construction and move
assignment. Those with an X in column S use swap, in column MC use move
construction, and in column MA use move assignment. Many of them can
make use of all three.
You just labeled std::sort as exotic. :-)
There's few functions in there that *only* use swap, and not move
construction or move assignment. These include:
reverse
random_shuffle
partition
next_permutation
prev_permutation
> There is only one remaining question related to pt.1 a page above: is it
> possible to break code due to a compiler generated move-op, if a class
> consists of std lib classes and has no user-defined copy-op?
> I won't think so but I can't proof it either.
<nod> Just stumbled over one. I've been working the threading area
lately so that's on my mind.
Consider:
class thread_pool
{
std::vector<thread> threads_;
...
public:
...
};
Then intent of the author is that thread_pool is neither movable nor
copyable. It must communicate with remotely controlled data structures
which point back to this thread_pool. Now one could make such a
thread_pool movable, by alerting those remote structures of the move.
But this author has chosen not to.
By the current rvalue-ref language rules in the working draft, the above
(admittedly sketchy) prototype is sufficient to prohibit moving and
copying of thread_pool. thread is a move-only handle. And that makes
std::vector<thread> a move-only object (copy constructor is ill formed).
Now if we implicitly auto-generate move members for thread_pool, then
those members will access the undesired move members of
std::vector<thread>. thread_pool becomes movable, but with the improper
logic. The remote structures remain unaware that their reference back
to the thread_pool is now dangling. We've turned what thread_pool's
author intended to be a compile time error into a run time error.
-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 ]
Author: "W Karas" <wkaras@yahoo.com>
Date: Mon, 5 Mar 2007 08:12:29 CST Raw View
On Feb 20, 12:38 pm, "W Karas" <wka...@yahoo.com> wrote:
> Add this pseudo class template
> to the std namespace:
>
> template <typename T>
> class rvalue;
>
> For any type X, the types X and rvalue<X>
> would be distinct but have exactly the
> same interface/size/alignment. For
> value/reference/pointer conversion, both
> would convert to const X implicitly, but
> conversion between them would require a static cast.
>
> Anonymous, compiler-generated temporary instances
> (r-values) would be of type rvalue<X>. This seems
> to solve the forwarding problem, because
> template type deduction would capture the
> difference between a const reference and a
> temporary (without changes to the deduction
> rules).
>
> A named instance of rvalue<X> would save one cast
> in a swap:
>
> std::rvalue<X> t = static_cast<std::rvalue<X> &>(a);
> a = static_cast<std::rvalue<X> &>(b);
> b = t;
At the cost of adding a new reserve word, "rvalue" could
become a type modifier like "const" and "volatile".
This seems more intuitive, and presents an obvious
solution to how to declare member functions where
the instance itself is expected to be an rvalue:
void foo(void) rvalue;
analogous to:
void foo(void) const;
---
[ 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 ]
Author: "=?iso-8859-1?q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Mon, 5 Mar 2007 12:44:53 CST Raw View
On Mar 5, 3:12 pm, "W Karas" <wka...@yahoo.com> wrote:
> On Feb 20, 12:38 pm, "W Karas" <wka...@yahoo.com> wrote:
> > Add this pseudo class template
> > to the std namespace:
>
> > template <typename T>
> > class rvalue;
>
> > For any type X, the types X and rvalue<X>
> > would be distinct but have exactly the
> > same interface/size/alignment. For
> > value/reference/pointer conversion, both
> > would convert to const X implicitly, but
> > conversion between them would require a static cast.
>
> > Anonymous, compiler-generated temporary instances
> > (r-values) would be of type rvalue<X>. This seems
> > to solve the forwarding problem, because
> > template type deduction would capture the
> > difference between a const reference and a
> > temporary (without changes to the deduction
> > rules).
>
> > A named instance of rvalue<X> would save one cast
> > in a swap:
>
> > std::rvalue<X> t = static_cast<std::rvalue<X> &>(a);
> > a = static_cast<std::rvalue<X> &>(b);
> > b = t;
It would be nice, if you could explain your reasons,
why your proposed class template rvalue is better
than the current rvalue proposal? The most recent
document is here:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html
This one corresponds to the primary proposal:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html
and these are some intermediates, which explain also library
impact:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1770.html
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1771.html
> At the cost of adding a new reserve word, "rvalue" could
> become a type modifier like "const" and "volatile".
> This seems more intuitive, and presents an obvious
> solution to how to declare member functions where
> the instance itself is expected to be an rvalue:
>
> void foo(void) rvalue;
>
> analogous to:
>
> void foo(void) const;
What is the advantage of an rvalue-function foo? What should
it do that should not be done for const, volatile, or not-cv-not-
rvalue
types?
The rvalue proposal allow selected member functions to support
move-semantic, e.g.
struct C {
C(C&& rhs);
void swap(C&& other);
};
Isn't this sufficient?
Greetings from Bremen,
Daniel Kr gler
---
[ 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 ]
Author: "W Karas" <wkaras@yahoo.com>
Date: Tue, 6 Mar 2007 08:36:59 CST Raw View
On Mar 5, 1:44 pm, "Daniel Kr gler" <daniel.krueg...@googlemail.com>
wrote:
> On Mar 5, 3:12 pm, "W Karas" <wka...@yahoo.com> wrote:
>
>
>
>
>
> > On Feb 20, 12:38 pm, "W Karas" <wka...@yahoo.com> wrote:
> > > Add this pseudo class template
> > > to the std namespace:
>
> > > template <typename T>
> > > class rvalue;
>
> > > For any type X, the types X and rvalue<X>
> > > would be distinct but have exactly the
> > > same interface/size/alignment. For
> > > value/reference/pointer conversion, both
> > > would convert to const X implicitly, but
> > > conversion between them would require a static cast.
>
> > > Anonymous, compiler-generated temporary instances
> > > (r-values) would be of type rvalue<X>. This seems
> > > to solve the forwarding problem, because
> > > template type deduction would capture the
> > > difference between a const reference and a
> > > temporary (without changes to the deduction
> > > rules).
>
> > > A named instance of rvalue<X> would save one cast
> > > in a swap:
>
> > > std::rvalue<X> t = static_cast<std::rvalue<X> &>(a);
> > > a = static_cast<std::rvalue<X> &>(b);
> > > b = t;
>
> It would be nice, if you could explain your reasons,
> why your proposed class template rvalue is better
> than the current rvalue proposal? The most recent
> document is here:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html
>
> This one corresponds to the primary proposal:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html
>
> and these are some intermediates, which explain also library
> impact:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1770.htmlhttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1771.html
It's unfortunate that there is not an up-to-date, comprehensive
written description (ideally including a tutorial) of the rvalue
reference proposal.
It's clear that both rvalue references and rvalue types would
interact with existing features of C++ in complex ways. I
think it's very possible that rvalue types would be somewhat
less complex. I don't have time to really investigate
this. But maybe someone else does, so I put out the
suggestion.
>
> > At the cost of adding a new reserve word, "rvalue" could
> > become a type modifier like "const" and "volatile".
> > This seems more intuitive, and presents an obvious
> > solution to how to declare member functions where
> > the instance itself is expected to be an rvalue:
>
> > void foo(void) rvalue;
>
> > analogous to:
>
> > void foo(void) const;
>
> What is the advantage of an rvalue-function foo? What should
> it do that should not be done for const, volatile, or not-cv-not-
> rvalue
> types?
I read in some posting that a problem with the rvalue
reference proposal was how to declare a member function
that could only be called when the class instance was
an rvalue.
> The rvalue proposal allow selected member functions to support
> move-semantic, e.g.
>
> struct C {
> C(C&& rhs);
> void swap(C&& other);
>
> };
>
> Isn't this sufficient?
'swap(rvalue C &other)' seems more intuitive to me. For
function template type deduction:
template<typename T>
void foo(T &x) ...
if I call foo passing an rvalue of type X, it seems more
intuitive to deduce T to be 'rvalue X' rather than 'X &'.
---
[ 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 ]
Author: howard.hinnant@gmail.com (Howard Hinnant)
Date: Tue, 6 Mar 2007 17:40:53 GMT Raw View
In article <1173184878.379660.46460@h3g2000cwc.googlegroups.com>,
"W Karas" <wkaras@yahoo.com> wrote:
> It's unfortunate that there is not an up-to-date, comprehensive
> written description (ideally including a tutorial) of the rvalue
> reference proposal.
Fwiw:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html
> I read in some posting that a problem with the rvalue
> reference proposal was how to declare a member function
> that could only be called when the class instance was
> an rvalue.
There is a proposal for this functionality:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1821.htm
According to:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2142.html
N1821 has stalled in the committee.
> > The rvalue proposal allow selected member functions to support
> > move-semantic, e.g.
> >
> > struct C {
> > C(C&& rhs);
> > void swap(C&& other);
> >
> > };
> >
> > Isn't this sufficient?
>
> 'swap(rvalue C &other)' seems more intuitive to me.
<shrug>The currently proposed syntax was chosen so as to avoid the need
to introduce new keywords. Syntax such as you suggest was considered.
> For
> function template type deduction:
>
> template<typename T>
> void foo(T &x) ...
>
> if I call foo passing an rvalue of type X, it seems more
> intuitive to deduce T to be 'rvalue X' rather than 'X &'.
Fwiw, in the current C++ and proposed C++0X, passing an rvalue X to your
templated foo results in a compile time error. I think it is a
non-starter to start having foo(T&) compile when passed an rvalue. This
would prove dangerous to existing code which relies on that use case not
compiling.
However:
template <typename T>
void foo(T&& x) ...
Now passing an rvalue X compiles and T is deduced as X.
You may be referring to the part of the proposed C++0X which says: If
you pass an lvalue X to foo, T is deduced as X&.
I agree this is somewhat non-intuitive. However it sure has solved a
lot of problems while making the client-level code very intuitive and
functional.
-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 ]
Author: "W Karas" <wkaras@yahoo.com>
Date: Tue, 6 Mar 2007 22:10:38 CST Raw View
On Mar 6, 12:40 pm, howard.hinn...@gmail.com (Howard Hinnant) wrote:
> In article <1173184878.379660.46...@h3g2000cwc.googlegroups.com>,
> "W Karas" <wka...@yahoo.com> wrote:
.
>
> > 'swap(rvalue C &other)' seems more intuitive to me.
>
> <shrug>The currently proposed syntax was chosen so as to avoid the need
> to introduce new keywords. Syntax such as you suggest was considered.
.
Seems like there's lots of new kewords in C++09 anyway. But, if
rvalue types are otherwise superior to rvalue references, I would
vote for introducing the weird notion of a scoped keyword:
swap(std::rvalue C &other)
if making rvalue a "normal" keyword is unacceptable.
---
[ 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 ]
Author: "W Karas" <wkaras@yahoo.com>
Date: Tue, 20 Feb 2007 11:38:39 CST Raw View
Add this pseudo class template
to the std namespace:
template <typename T>
class rvalue;
For any type X, the types X and rvalue<X>
would be distinct but have exactly the
same interface/size/alignment. For
value/reference/pointer conversion, both
would convert to const X implicitly, but
conversion between them would require a static cast.
Anonymous, compiler-generated temporary instances
(r-values) would be of type rvalue<X>. This seems
to solve the forwarding problem, because
template type deduction would capture the
difference between a const reference and a
temporary (without changes to the deduction
rules).
A named instance of rvalue<X> would save one cast
in a swap:
std::rvalue<X> t = static_cast<std::rvalue<X> &>(a);
a = static_cast<std::rvalue<X> &>(b);
b = t;
---
[ 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 ]