Topic: rvalue references returned from a function
Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Mon, 6 Jul 2009 09:27:51 CST Raw View
Niels Dekker - no reply address wrote:
> Dragan Milenkovic wrote:
>> What are smart reasons for a function to return a rvalue reference?
>
> Suppose Foo is a lightweight wrapper of an R object. Its job is to
> initialize the R object it holds, and pass a reference-to-R to the user, by
> Foo::get_data(). In that case it would be useful to have Foo::get_data()
> return an rvalue reference, if the Foo-object itself is an rvalue:
>
> class Foo {
> R m_data;
> public:
> Foo();
> R & get_data() & { return m_data; }
> R && get_data() &&; { return m_data; }
> R const & get_data() const & { return m_data; }
> R const && get_data() const && { return m_data; }
> };
>
> // Should "move", using R::R(R&&):
> R result = Foo().get_data();
Niels Dekker - no reply address wrote:
> Dragan Milenkovic wrote:
>> So, in conclusion... There doesn't seem to be a smart reason
>> to return a rvalue reference in _most_ of the designs.
>
> IMO, it would certainly be useful to have overloaded versions of STL
> container member functions like operator[](size_type), at(size_type),
> front(), and back() that return an rvalue-reference to the specified
> container element, if the container itself is an rvalue.
Thank you for both posts. I understand your reasoning. However, one
argument in the mentioned discussions (links provided below)
was that someone can do:
const R & = Foo().get_data();
... and get a dangling reference.
But another "however"... GCC seem to make a temporary, either by
moving (if move-ctor exists) or by making a copy, when binding
"const R &" to the result of the expression. If I'm not mistaken,
this makes no dangling references both in this example and earlier
mentioned "R && operator+(R &&, const R &)".
Is this behavior in contradiction to the standard? Would forcing
such a behavior be a reason to allow mentioned "operator+"?
Of course...
R && r = R(1) + R(2);
... would still result in a dangling reference, but why would anyone
use a rvalue reference here? I remember a sentence from the document
that introduced me to rvalue references: "You don't ever want to bind
a temporary to a non-const reference ... except when you do" (N1377)
Like it says - don't bind to "R &&" unless you're sure you got it right.
Just thinking out loud, I'm sure there is already an answer to all this.
Many thanks, people...
>> SG wrote:
>>> There were two discussions about this in clc++m and/or clsc++ if I
>>> remember correctly. I started both.
>>
>> Interesting. Which discussions do you exactly refer to?
This is what I have found. I think SG referred to another discussion,
but these two did the job so far...
http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/e0eb9f08decb5395/
http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/99ae7ed3b6b4548e/
--
Dragan
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Mon, 6 Jul 2009 09:28:16 CST Raw View
On 5 Jul., 16:58, "Niels Dekker - no reply address"
<inva...@this.is.invalid> wrote:
> SG wrote:
> > There were two discussions about this in clc++m and/or clsc++ if I
> > remember correctly. I started both.
>
> Interesting. Which discussions do you exactly refer to?
Here there are:
http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/99ae7ed3b6b4548e
http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/9b8ac2c3745d889e
> > discussion with a little summary about why recycling of temporaries
> > doesn't work safely and a hypothetical language feature which could
> > solve the "problem". It was something like this:
>
> > auto increment(R x) -> x
> > { x.value += 1; }
>
> Which would be equivalent to:
>
> template <qualifiers Q> // hypothetical!
> R Q increment(R Q x);
> { x.value += 1; return x; }
>
> I guess ;-)
Not exactly. It doesn't recycle the temporary while making
R const& ref = increment(R(1));
safe, does it? The point of
auto increment(R x) -> x;
was to augment the signature to include the information that parameter
and return value are the same object. This allows the compiler to
extend the temporary's life-time and make 'ref' a non-dangling
reference.
The qualifiers template parameter was an attempt to get rid of the
increasing number of special cases of member function pointers you
have to handle in std::mem_fun and std::bind.
Cheers!
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Thomas Petit <thomas.petit33@gmail.com>
Date: Mon, 6 Jul 2009 09:33:39 CST Raw View
On 5 juil, 10:36, SG <s.gesem...@gmail.com> wrote:
>
> Even though something like this (one of string's operator+ functions
> returned string&&) was an example of an early rvalue reference
> proposal it is now considered buggy code. The safe version would be
>
> R increment(R const & x) { return R(x.value+1); }
> R increment(R && x) { x.value += 1; return move(x); }
>
Thanks for the clarification.
Could you explained one more example of rvalue references returned
from a function ?
It's in the early proposal to add some algorithm from
Boost.String.Algo into the TR2 :
<---------------------------------
Differences from the Boost String Algorithms Library :
Mutable variants of algorithms were removed in favor of move semantics
(using constructs form the proposal N1770). Now the algorithms usually
come in two flavors, a copy (using const &) and a move (using &&)
variant. We consider this to be another evolutionary step towards
functional-oriented programming in C++. During the review of Boost
String Algorithms Library this topic was intensely debated. A strong
opinion was expressed in favor of functional approach, however without
the move semantics support, it is not possible to implement certain
algorithms in an efficient manner. Therefore mutable version were
retained as a primary interface, accompanied by copy variants.
<----------------------------------
For example, in this proposal, trim_left come in two flavor :
<--------------------------------------
template<typename CopyableRange>
CopyableRange trim_left(const CopyableRange& s);
template<typename Sequence>
Sequence&& trim_left(Sequence&& s);
<--------------------------------------
But, I suppose that "Sequence&& trim_left(Sequence&& s);" is dangerous
in the same way as the string's operator+ which returned string&&.
So, what would be the correct way to write trim_left, if we want a
functional style for it ?
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Niels Dekker - no reply address" <noreply@this.is.invalid>
Date: Mon, 6 Jul 2009 13:10:23 CST Raw View
class Foo {
R m_data;
public:
Foo();
R & get_data() & { return m_data; }
R && get_data() &&; { return m_data; }
R const & get_data() const & { return m_data; }
R const && get_data() const && { return m_data; }
};
// Should "move", using R::R(R&&):
R result = Foo().get_data();
Dragan Milenkovic wrote:
Thank you for both posts. I understand your reasoning. However, one
argument in the mentioned discussions (links provided below)
was that someone can do:
const R & = Foo().get_data();
... and get a dangling reference.
[std::max(unsigned, size_t), amd64 and C++0x]
http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/e0eb9f08decb5395/
[C++0x: returning rvalue references, recycling temporaries]
http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/99ae7ed3b6b4548e/
You're welcome. But I think the subject of those discussions was
slightly different, as they did not deal specifically with member
functions, returning a reference to internal member data. When
retrieving a reference from such a member function, you always have to
be careful, not to leave it dangling around. In C++03 as well as in
C++0x.
Or would you prefer to "disable" calling such a member function on an
rvalue object, in C++0x?
class Foo {
void get_data() && = delete ;
void get_data() const && = delete ;
public:
R & get_data() & { return m_data; }
R const & get_data() const & { return m_data; }
};
And likewise, would you prefer to have container member functions like
operator[], at(size_type), front(), and back() deleted for rvalue
containers? Personally, I'd rather not!
But another "however"... GCC seem to make a temporary, either by
moving (if move-ctor exists) or by making a copy, when binding
"const R &" to the result of the expression. If I'm not mistaken,
this makes no dangling references both in this example and earlier
mentioned "R && operator+(R &&, const R &)".
Is this behavior in contradiction to the standard? Would forcing
such a behavior be a reason to allow mentioned "operator+"?
I'd have to see a complete, compilable example...
Kind regards, Niels
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: darkmx <micael.dark@gmail.com>
Date: Mon, 6 Jul 2009 18:15:41 CST Raw View
On 6 jul, 10:33, Thomas Petit <thomas.peti...@gmail.com> wrote:
> On 5 juil, 10:36, SG <s.gesem...@gmail.com> wrote:
>
>
>
> > Even though something like this (one of string's operator+ functions
> > returned string&&) was an example of an early rvalue reference
> > proposal it is now considered buggy code. The safe version would be
>
> > R increment(R const & x) { return R(x.value+1); }
> > R increment(R && x) { x.value += 1; return move(x); }
>
> Thanks for the clarification.
> Could you explained one more example of rvalue references returned
> from a function ?
> It's in the early proposal to add some algorithm from
> Boost.String.Algo into the TR2 :
>
> <---------------------------------
> Differences from the Boost String Algorithms Library :
>
> Mutable variants of algorithms were removed in favor of move semantics
> (using constructs form the proposal N1770). Now the algorithms usually
> come in two flavors, a copy (using const &) and a move (using &&)
> variant. We consider this to be another evolutionary step towards
> functional-oriented programming in C++. During the review of Boost
> String Algorithms Library this topic was intensely debated. A strong
> opinion was expressed in favor of functional approach, however without
> the move semantics support, it is not possible to implement certain
> algorithms in an efficient manner. Therefore mutable version were
> retained as a primary interface, accompanied by copy variants.
> <----------------------------------
>
> For example, in this proposal, trim_left come in two flavor :
>
> <--------------------------------------
> template<typename CopyableRange>
> CopyableRange trim_left(const CopyableRange& s);
>
> template<typename Sequence>
> Sequence&& trim_left(Sequence&& s);
> <--------------------------------------
>
> But, I suppose that "Sequence&& trim_left(Sequence&& s);" is dangerous
> in the same way as the string's operator+ which returned string&&.
>
> So, what would be the correct way to write trim_left, if we want a
> functional style for it ?
>
> --
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ:http://www.comeaucomputing.com/csc/faq.html ]
HI all. I'm currently reimplementing my B.S. thesis (several thousands
lines of code) using gcc 4.4.0 C++0x . I got bitten by this:
const int& create( )
{
auto ptr = new int( );
std::printf("address inside creator: %d\n", ptr);
return *ptr;
}
void f(const int& n)
{
std::printf("address inside function: %d\n", &n);
}
int main( )
{
f(std::move(create( )));
}
and it prints the unexpected (to me)
// address inside creator: #4006984
// address inside function: #2293596
if I change main to
int main( )
{
f(create( ));
}
(without std::move) it prints
// address inside creator: #4006984
// address inside function: #4006984
I expected std::move of a const T& to be basically a no-op but it
appears to be creating a hidden temporary
Am I missing something? =\ current wording is
template <RvalueOf T> RvalueOf<T>::type move(T&& t);
Returns: t.
and gcc implementation is
template<typename _Tp>
inline typename std::remove_reference<_Tp>::type&&
move(_Tp&& __t)
{ return __t; }
n2027 specifies
The move function really does very little work. All move does is
accept either an lvalue or rvalue argument, and return it as an rvalue
without triggering a copy construction
If the behavior is intended, its -really- counterintuitive!
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Mon, 6 Jul 2009 22:22:58 CST Raw View
Niels Dekker - no reply address wrote:
[snip]
> You're welcome. But I think the subject of those discussions was
> slightly different, as they did not deal specifically with member
> functions, returning a reference to internal member data. When
> retrieving a reference from such a member function, you always have to
> be careful, not to leave it dangling around. In C++03 as well as in
> C++0x.
>
> Or would you prefer to "disable" calling such a member function on an
> rvalue object, in C++0x?
>
> class Foo {
> void get_data() && = delete ;
> void get_data() const && = delete ;
> public:
> R & get_data() & { return m_data; }
> R const & get_data() const & { return m_data; }
> };
>
> And likewise, would you prefer to have container member functions like
> operator[], at(size_type), front(), and back() deleted for rvalue
> containers? Personally, I'd rather not!
I'm now fairly convinced that there should exist && overloads and that
the user should be careful with it.
But doesn't the same argument about "being careful" hold even in the
case of operator+ ? Of course, it is not completely identical.
However, IMHO there is some parallel between:
- knowing whether get_data() returns a (copied) value or a reference
- and knowing if operator+ can sometimes return a rvalue reference
to a temporary that will be gone with the current expression
(which translates to simply - don't bind to a reference)
> But another "however"... GCC seem to make a temporary, either by
> moving (if move-ctor exists) or by making a copy, when binding
> "const R &" to the result of the expression. If I'm not mistaken,
> this makes no dangling references both in this example and earlier
> mentioned "R && operator+(R &&, const R &)".
>
> Is this behavior in contradiction to the standard? Would forcing
> such a behavior be a reason to allow mentioned "operator+"?
>
>
> I'd have to see a complete, compilable example...
struct R {
R() { std::cout << "ctor " << this << std::endl; }
R(const R &) { std::cout << "copy " << this << std::endl; }
R(R &&) { std::cout << "move " << this << std::endl; }
~R() { std::cout << "dtor " << this << std::endl; }
};
class Foo {
R m_data;
public:
Foo() {}
R && get_data() { return std::move(m_data); }
};
int main() {
const R & r = Foo().get_data();
std::cout << "using " << &r << std::endl;
}
output:
ctor 0x7fff23a20ec7
move 0x7fff23a20ec6
dtor 0x7fff23a20ec7
using 0x7fff23a20ec6
dtor 0x7fff23a20ec6
--
Dragan
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Tue, 7 Jul 2009 20:39:31 CST Raw View
darkmx wrote:
[snip]
>
> HI all. I'm currently reimplementing my B.S. thesis (several thousands
> lines of code) using gcc 4.4.0 C++0x . I got bitten by this:
>
>
> const int& create( )
> {
> auto ptr = new int( );
> std::printf("address inside creator: %d\n", ptr);
>
> return *ptr;
> }
>
> void f(const int& n)
> {
> std::printf("address inside function: %d\n", &n);
> }
>
>
> int main( )
> {
> f(std::move(create( )));
> }
>
> and it prints the unexpected (to me)
> // address inside creator: #4006984
> // address inside function: #2293596
[snip]
>
> n2027 specifies
> The move function really does very little work. All move does is
> accept either an lvalue or rvalue argument, and return it as an rvalue
> without triggering a copy construction
>
> If the behavior is intended, its -really- counterintuitive!
Actually it is not, you just require a pointer to the right direction...
Binding to a lvalue reference to const is allowed to create a temporary.
If this creates a problem for you, make the parameter a reference to
non-const, or even use pointers (since you are interested in
addresses).
My guess is that in your real code, you are not allocating an integer,
but a more complex type. Therefore, IMHO the best approach would be
to use std::shared_ptr<Type> and pass _that_ around.
A lvalue reference to const usually indicates pass-by-value.
Also, std::move is used when working with values, too. When working
with value semantics, you should not care about addresses and copying
in the way you are trying to care.
--
Dragan
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Niels Dekker - no reply address" <invalid@this.is.invalid>
Date: Tue, 7 Jul 2009 22:48:54 CST Raw View
Dragan Milenkovic wrote:
>> But another "however"... GCC seem to make a temporary, either by
>> moving (if move-ctor exists) or by making a copy, when binding
>> "const R &" to the result of the expression.
[...]
> struct R {
> R() { std::cout << "ctor " << this << std::endl; }
> R(const R &) { std::cout << "copy " << this << std::endl; }
> R(R &&) { std::cout << "move " << this << std::endl; }
> ~R() { std::cout << "dtor " << this << std::endl; }
> };
>
> class Foo {
> R m_data;
>
> public:
> Foo() {}
>
> R && get_data() { return std::move(m_data); }
> };
>
> int main() {
> const R & r = Foo().get_data();
>
> std::cout << "using " << &r << std::endl;
> }
>
> output:
> ctor 0x7fff23a20ec7
> move 0x7fff23a20ec6
> dtor 0x7fff23a20ec7
> using 0x7fff23a20ec6
> dtor 0x7fff23a20ec6
This looks like a compiler bug to me. I just had a look at 8.5.3
References, [dcl.init.ref], and I think the following applies:
- If the initializer expression is an rvalue, with T2 a class type, and
"cv1 T1" is reference-compatible with "cv2 T2," the reference is bound to
the object represented by the rvalue (see 3.10) or to a sub-object within
that object
(From www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2914.pdf)
Microsoft Visual C++ 2010 Beta 1 outputs the following:
ctor 0012FE8B
dtor 0012FE8B
using 0012FE8B
Which looks more intuitive to me. OTOH, MSVC emits a warning that I find a
bit strange:
R && get_data()
{
// warning C4172: returning address of local variable or temporary
return std::move(m_data);
}
Hopefully MSVC won't emit such a warning when R&& unique_future<R>::get() is
instantiated...
Anyway, apparently you've found a GCC bug, so maybe you should submit a bug
report to http://gcc.gnu.org/bugzilla (if it hasn't been reported before).
I found a similar issue here:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34022 But that's about built-in
types, so it's more like the example darkmx (micael.dark) posted here.
Good luck!
Niels
--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: darkmx <micael.dark@gmail.com>
Date: Wed, 8 Jul 2009 04:56:13 CST Raw View
On 7 jul, 21:39, Dragan Milenkovic <dra...@plusplus.rs> wrote:
> darkmx wrote:
>
> [snip]
>
>
>
>
>
>
>
> > HI all. I'm currently reimplementing my B.S. thesis (several thousands
> > lines of code) using gcc 4.4.0 C++0x . I got bitten by this:
>
> > const int& create( )
> > {
> > auto ptr = new int( );
> > std::printf("address inside creator: %d\n", ptr);
>
> > return *ptr;
> > }
>
> > void f(const int& n)
> > {
> > std::printf("address inside function: %d\n", &n);
> > }
>
> > int main( )
> > {
> > f(std::move(create( )));
> > }
>
> > and it prints the unexpected (to me)
> > // address inside creator: #4006984
> > // address inside function: #2293596
>
> [snip]
>
>
>
> > n2027 specifies
> > The move function really does very little work. All move does is
> > accept either an lvalue or rvalue argument, and return it as an rvalue
> > without triggering a copy construction
>
> > If the behavior is intended, its -really- counterintuitive!
>
> Actually it is not, you just require a pointer to the right direction...
>
> Binding to a lvalue reference to const is allowed to create a temporary.
> If this creates a problem for you, make the parameter a reference to
> non-const, or even use pointers (since you are interested in
> addresses).
>
> My guess is that in your real code, you are not allocating an integer,
> but a more complex type. Therefore, IMHO the best approach would be
> to use std::shared_ptr<Type> and pass _that_ around.
>
> A lvalue reference to const usually indicates pass-by-value.
> Also, std::move is used when working with values, too. When working
> with value semantics, you should not care about addresses and copying
> in the way you are trying to care.
>
> --
> Dragan
>
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ:http://www.comeaucomputing.com/csc/faq.html ]
8.5.3 states
"If the initializer expression is an rvalue, with T2 a class type, and
cv1 T1 is reference-compatible
with cv2 T2, the reference is bound to the object represented by the
rvalue (see 3.10) or to a
sub-object within that object.
...
Otherwise, a temporary of type cv1 T1 is created and initialized
from the initializer expression
using the rules for a non-reference copy initialization (8.5). The
reference is then bound to the
temporary."
its core defect 391, so after all, I think its a gcc bug (and enforces
my opinion that gcc current behavior is counter-intuitive :) )
Im actually allocating integers and some other simple variables, so I
didn't notice till I experienced an ugly segmentation fault (btw, I
typed std::move by mistake, it wasn't needed, but the error was hard
to catch).
I completely agree that pointers are a better choice here from an
implementation of view, but for my specific application, using const
references makes the code look nicer and more evident (from a high-
level semantic point of view)
thanks for your reply
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Thu, 9 Jul 2009 08:59:27 CST Raw View
Dragan Milenkovic wrote:
> darkmx wrote:
> [snip]
>>
>> HI all. I'm currently reimplementing my B.S. thesis (several thousands
>> lines of code) using gcc 4.4.0 C++0x . I got bitten by this:
>>
>>
>> const int& create( )
>> {
>> auto ptr = new int( );
>> std::printf("address inside creator: %d\n", ptr);
>>
>> return *ptr;
>> }
>>
>> void f(const int& n)
>> {
>> std::printf("address inside function: %d\n", &n);
>> }
>>
>>
>> int main( )
>> {
>> f(std::move(create( )));
>> }
>>
>> and it prints the unexpected (to me)
>> // address inside creator: #4006984
>> // address inside function: #2293596
>
> [snip]
>>
>> n2027 specifies
>> The move function really does very little work. All move does is
>> accept either an lvalue or rvalue argument, and return it as an rvalue
>> without triggering a copy construction
>>
>> If the behavior is intended, its -really- counterintuitive!
>
> Actually it is not, you just require a pointer to the right direction...
>
> Binding to a lvalue reference to const is allowed to create a temporary.
> If this creates a problem for you, make the parameter a reference to
> non-const, or even use pointers (since you are interested in
> addresses).
>
> My guess is that in your real code, you are not allocating an integer,
> but a more complex type. Therefore, IMHO the best approach would be
> to use std::shared_ptr<Type> and pass _that_ around.
>
> A lvalue reference to const usually indicates pass-by-value.
> Also, std::move is used when working with values, too. When working
> with value semantics, you should not care about addresses and copying
> in the way you are trying to care.
Actually, I spoke rather too soon. There might be issues with GCC
as pointed by Niels Dekker in the thread "rvalue references returned
from a function". Apparently, you and I stumbled on the same
bug at the same time, except I assumed GCC does the right thing
since binding to a rvalue to a lvalue reference to const is nothing
new.
Apparently I thought that binding a rvalue to a lvalue reference
to const was allowed but not required to create a temporary,
even in the case where source and destination are reference compatible.
As Niels Dekker pointed out, this is not the case - such behavior
is prohibited. I will file a bug report :-)
--
Dragan
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Thu, 9 Jul 2009 08:51:37 CST Raw View
Niels Dekker - no reply address wrote:
[snip]
>
> This looks like a compiler bug to me. I just had a look at 8.5.3
> References, [dcl.init.ref], and I think the following applies:
> - If the initializer expression is an rvalue, with T2 a class type, and
> "cv1 T1" is reference-compatible with "cv2 T2," the reference is bound to
> the object represented by the rvalue (see 3.10) or to a sub-object within
> that object
> (From www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2914.pdf)
[snip]
> Anyway, apparently you've found a GCC bug, so maybe you should submit a bug
> report to http://gcc.gnu.org/bugzilla (if it hasn't been reported before).
> I found a similar issue here:
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34022 But that's about built-in
> types, so it's more like the example darkmx (micael.dark) posted here.
It's exactly the same problem he encountered. In the most recent
post he referred to:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#391
Had no idea the behavior changed. They should put this on the box! :-D
I'll submit a bug report with reference to these two discussions.
Thanks for all the help.
--
Dragan
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Thu, 9 Jul 2009 08:51:35 CST Raw View
darkmx wrote:
[snip]
>
> 8.5.3 states
>
> "If the initializer expression is an rvalue, with T2 a class type, and
> cv1 T1 is reference-compatible
> with cv2 T2, the reference is bound to the object represented by the
> rvalue (see 3.10) or to a
> sub-object within that object.
>
> ...
>
> Otherwise, a temporary of type cv1 T1 is created and initialized
> from the initializer expression
> using the rules for a non-reference copy initialization (8.5). The
> reference is then bound to the
> temporary."
>
> its core defect 391, so after all, I think its a gcc bug (and enforces
> my opinion that gcc current behavior is counter-intuitive :) )
I already sent a post stating that I made a mistake. However, now I see
that this is actually something that changed between C++03 and C++0x.
On the personal note, it was terrifying to find out that I had a flaw
in a very fundamental part of C++, but now it's all alright... :-)
Now it seems that I cannot file a bug report, but a feature
request instead.
> Im actually allocating integers and some other simple variables, so I
> didn't notice till I experienced an ugly segmentation fault (btw, I
> typed std::move by mistake, it wasn't needed, but the error was hard
> to catch).
>
> I completely agree that pointers are a better choice here from an
> implementation of view, but for my specific application, using const
> references makes the code look nicer and more evident (from a high-
> level semantic point of view)
It's just that I got impression that you are closer to value semantics
(std::move and const reference pointed to that), and thought that
you could use integers as values instead of dynamically allocating
them. But it's just a thought, nothing intrusive...
Thanks a lot for pointing to the defect report! :-)
--
Dragan
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Ed Smith-Rowland <3dw4rd@verizon.net>
Date: Thu, 9 Jul 2009 12:31:45 CST Raw View
On Jul 5, 2:26 am, Dragan Milenkovic <dra...@plusplus.rs> wrote:
> I would appreciate a few pointers to rvalue references... :-D
> What are smart reasons for a function to return a rvalue reference?
>
> Example:
>
> class Foo {
> public:
> R && func_1();
> R const && func_2();
> };
>
> I understand when it would be valid or invalid. But what are
> use cases or designs that benefit from such return values?
>
> The one case I know is - "reusing" a rvalue function parameter:
> R increment(R const & x) { return R(x.value+1); }
> R && increment(R && x) { x.value += 1; return x; }
>
> ... but then again... this is UB, isn't it?
>
> const R & x = increment(R(1));
>
> Thanks for your time...
>
> --
> Dragan
>
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ:http://www.comeaucomputing.com/csc/faq.html ]
I've always thought you could use it as a factory. It would be more
efficient than return by value for an expensive object.
BigThing &&
makeBigThing( const Input & in, ... )
{
...
BigThing thing(...);
...
return std::move(thing);
}
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Thu, 9 Jul 2009 14:24:42 CST Raw View
On 9 Jul., 20:31, Ed Smith-Rowland <3dw...@verizon.net> wrote:
> I've always thought you could use it as a factory. It would be more
> efficient than return by value for an expensive object.
>
> BigThing &&
> makeBigThing( const Input & in, ... )
> {
> ...
> BigThing thing(...);
> ...
> return std::move(thing);
> }
thing is an automatic object. Its lifetime ends when the function
returns. So, the function's return value is a dangling reference. In
this respect, there is no difference between rvalue references and
lvalue references.
*Never ever* return references to function-local automatic objects --
regardless of the type of reference.
If BigThing has an efficient move-constructor the following function
is just going to be fine:
BigThing
makeBigThing( const Input & in, ... )
{
...
BigThing thing(...);
...
return thing;
}
Note that I changed the function's return type *and* removed
std::move. std::move is not necessary in this case because function-
local automatic objects are already considered rvalues in a return
expression. The use of std::move might even prevent the compiler from
performing the named return value optimization.
Cheers!
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Sun, 5 Jul 2009 00:26:29 CST Raw View
I would appreciate a few pointers to rvalue references... :-D
What are smart reasons for a function to return a rvalue reference?
Example:
class Foo {
public:
R && func_1();
R const && func_2();
};
I understand when it would be valid or invalid. But what are
use cases or designs that benefit from such return values?
The one case I know is - "reusing" a rvalue function parameter:
R increment(R const & x) { return R(x.value+1); }
R && increment(R && x) { x.value += 1; return x; }
... but then again... this is UB, isn't it?
const R & x = increment(R(1));
Thanks for your time...
--
Dragan
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Sun, 5 Jul 2009 02:36:26 CST Raw View
On 5 Jul., 08:26, Dragan Milenkovic <dra...@plusplus.rs> wrote:
>
> The one case I know is - "reusing" a rvalue function parameter:
> R increment(R const & x) { return R(x.value+1); }
> R && increment(R && x) { x.value += 1; return x; }
This doesn't compile anymore due to the new rvalue reference binding
rules. It must be "return move(x);" instead.
>
> ... but then again... this is UB, isn't it?
>
> const R & x = increment(R(1));
Using x is UB because it's a dangling reference. The problem here is
that if you recycle an rvalue like this the compiler doesn't know that
the returned rvalue reference still refers to the same temporary. It
could refer to any object. This information is simply not part of the
function's signature. So, the compiler cannot apply the life-time
extension rule.
Even though something like this (one of string's operator+ functions
returned string&&) was an example of an early rvalue reference
proposal it is now considered buggy code. The safe version would be
R increment(R const & x) { return R(x.value+1); }
R increment(R && x) { x.value += 1; return move(x); }
There were two discussions about this in clc++m and/or clsc++ if I
remember correctly. I started both. In the first discussion I was
basically asking the same question you asked now. I started the 2nd
discussion with a little summary about why recycling of temporaries
doesn't work safely and a hypothetical language feature which could
solve the "problem". It was something like this:
auto increment(R x) -> x
{ x.value += 1; }
In this case the function's signature contains all the necessary
information that allows the compiler to safely recycle temporaries:
The function accepts a parameter by value, possibly modifies it, and
returns it again. Also note that is doesn't require &&/const&-
overloads. This naturally extends to member functions:
auto R::operator+=(R const& rhs) -> this
{ this->value += rhs.value; }
Unfortunately, this introduces another class of functions which
doesn't seem to fit well into the type system we already have. What
would be the type of a function pointer that can hold the address of
increment? I don't know...
IMHO, the most satisfying implementation of increment is the one which
always return an object by value regardless of whether the argument
was an lvalue or an rvalue. The && overload isn't really necessary
unless the type R supports moving that is significantly faster than
copying.
Cheers!
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Sun, 5 Jul 2009 08:58:29 CST Raw View
SG wrote:
[snip]
> IMHO, the most satisfying implementation of increment is the one which
> always return an object by value regardless of whether the argument
> was an lvalue or an rvalue. The && overload isn't really necessary
> unless the type R supports moving that is significantly faster than
> copying.
I share your humble opinion :-) To add a reason - I don't like
the mentioned overloads for being asymmetric.
Anyway, thanks for the help. I found the discussions you mention.
Apparently it started with std::max issues. I like the fact that
it wasn't just me who had issues with operator+. However,
it's still in the WP...
So, in conclusion... There doesn't seem to be a smart reason
to return a rvalue reference in _most_ of the designs.
Now I just need to decipher what "R && unique_future<R>::get()"
stands for...
--
Dragan
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Niels Dekker - no reply address" <invalid@this.is.invalid>
Date: Sun, 5 Jul 2009 08:58:54 CST Raw View
Dragan Milenkovic wrote:
> What are smart reasons for a function to return a rvalue reference?
Suppose Foo is a lightweight wrapper of an R object. Its job is to
initialize the R object it holds, and pass a reference-to-R to the user, by
Foo::get_data(). In that case it would be useful to have Foo::get_data()
return an rvalue reference, if the Foo-object itself is an rvalue:
class Foo {
R m_data;
public:
Foo();
R & get_data() & { return m_data; }
R && get_data() &&; { return m_data; }
R const & get_data() const & { return m_data; }
R const && get_data() const && { return m_data; }
};
// Should "move", using R::R(R&&):
R result = Foo().get_data();
I'm not sure if the fourth overload (for const &&) is very useful. But
basically, you'd probably want the return value of get_data() to have the
same const/non-const and lvalue/rvalue-ref qualifier as the wrapper object
itself.
Unfortunately, it isn't particularly elegant and maintainable, having to
duplicate get_data() for each combination. SG has already suggested a
hypothetical new language feature, to avoid such code duplication: "Re:
N2855 and old std::MoveConstructible",
http://groups.google.com/group/comp.std.c++/browse_thread/thread/34be5e6762c69039
Using SG's hypothetical "qualifiers" keyword, /possibly/ as follows:
class Foo {
R m_data;
public:
Foo();
template <qualifiers Q> // hypothetical!
R Q get_data() Q { return m_data; }
};
SG wrote:
> There were two discussions about this in clc++m and/or clsc++ if I
> remember correctly. I started both.
Interesting. Which discussions do you exactly refer to?
> In the first discussion I was
> basically asking the same question you asked now. I started the 2nd
> discussion with a little summary about why recycling of temporaries
> doesn't work safely and a hypothetical language feature which could
> solve the "problem". It was something like this:
>
> auto increment(R x) -> x
> { x.value += 1; }
Which would be equivalent to:
template <qualifiers Q> // hypothetical!
R Q increment(R Q x);
{ x.value += 1; return x; }
I guess ;-)
Kind regards, Niels
--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Sun, 5 Jul 2009 17:07:36 CST Raw View
On Jul 5, 10:58 am, Dragan Milenkovic <dra...@plusplus.rs> wrote:
> SG wrote:
>
> [snip]
>
> > IMHO, the most satisfying implementation of increment is the one which
> > always return an object by value regardless of whether the argument
> > was an lvalue or an rvalue. The && overload isn't really necessary
> > unless the type R supports moving that is significantly faster than
> > copying.
>
> I share your humble opinion :-) To add a reason - I don't like
> the mentioned overloads for being asymmetric.
>
> Anyway, thanks for the help. I found the discussions you mention.
> Apparently it started with std::max issues. I like the fact that
> it wasn't just me who had issues with operator+. However,
> it's still in the WP...
This is issue 1138:
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#1138
> So, in conclusion... There doesn't seem to be a smart reason
> to return a rvalue reference in _most_ of the designs.
> Now I just need to decipher what "R && unique_future<R>::get()"
> stands for...
"_most_" is correct. Exceptions include move() and forward(). These
are functions whose interface implicitly says: "ground" this reference
before you hit the semicolon! In these cases making a copy, even if
done via a move, would defeat the purpose of the function.
-Howard
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Niels Dekker - no reply address" <invalid@this.is.invalid>
Date: Sun, 5 Jul 2009 17:07:16 CST Raw View
Dragan Milenkovic wrote:
> So, in conclusion... There doesn't seem to be a smart reason
> to return a rvalue reference in _most_ of the designs.
IMO, it would certainly be useful to have overloaded versions of STL
container member functions like operator[](size_type), at(size_type),
front(), and back() that return an rvalue-reference to the specified
container element, if the container itself is an rvalue.
> Now I just need to decipher what "R && unique_future<R>::get()"
> stands for...
Interesting. I guess the rvalue-reference is there to allow "moving" the
result provided by the unique_future.
unique_future<string> my_future = do_work_in_other_thread();
// ...
// Move-construct the result:
string result = my_future.get();
I guess you'd never call unique_future::get() more than once per
unique_future object. But I have to admit, I don't know enough about
futures, and the upcoming C++ thread support.
Kind regards, Niels
--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]