 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Ethan Eade Guest
|
Posted: Wed Jul 26, 2006 11:43 pm Post subject: reference to non-const temporary |
|
|
Consider the following: The failures apply to g++ 3.3.3 and 3.4, but
not 4.01, which happily compiles when line '***' is not present. Should
it always work according to the standard?
//-------------------------------------------------
struct Foo {
void foo() {}
operator Foo& () { return *this; } // ***
};
Foo make() { return Foo(); }
void use(Foo& foo) {}
int main()
{
// This line always works
make().foo();
// This line fails when *** is commented out
// using g++ 3.3.3 and 3.4
use(make());
}
//--------------------------------------------------
Regards,
Ethan Eade
---
[ 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 ] |
|
| Back to top |
|
 |
Greg Herlihy Guest
|
Posted: Wed Jul 26, 2006 11:49 pm Post subject: Re: reference to non-const temporary |
|
|
Ethan Eade wrote:
| Quote: | Consider the following: The failures apply to g++ 3.3.3 and 3.4, but
not 4.01, which happily compiles when line '***' is not present. Should
it always work according to the standard?
//-------------------------------------------------
struct Foo {
void foo() {}
operator Foo& () { return *this; } // ***
};
Foo make() { return Foo(); }
void use(Foo& foo) {}
int main()
{
// This line always works
make().foo();
// This line fails when *** is commented out
// using g++ 3.3.3 and 3.4
use(make());
}
|
The compiler should ignore the operator Foo&() conversion method when
converting a Foo to a Foo&, so whether the method is commented in or
out should make no difference to the compiler. Since a temporary cannot
be passed as a non-const reference parameter, the use() function call
should not compile successfully in both cases. (§12.3.2/1 prohibits a
conversion method from being called to convert an object to a reference
to the object's type.)
Greg
---
[ 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 ] |
|
| Back to top |
|
 |
Ethan Eade Guest
|
Posted: Thu Jul 27, 2006 8:55 am Post subject: Re: reference to non-const temporary |
|
|
Greg Herlihy wrote:
| Quote: | The compiler should ignore the operator Foo&() conversion method when
converting a Foo to a Foo&, so whether the method is commented in or
out should make no difference to the compiler. Since a temporary cannot
be passed as a non-const reference parameter, the use() function call
should not compile successfully in both cases. (§12.3.2/1 prohibits a
conversion method from being called to convert an object to a reference
to the object's type.)
|
Thanks -- so g++ 4.01 is wrong in this case.
I'm curious -- why aren't temporaries allowed to be passed as non-const
references? It seems slightly arbitrary, since non-const methods can be
called on them anyway. Surely such temporaries are fully constructed
objects. What's the rationale? It seems the restriction is trivially
circumvented using operator=():
struct Foo {};
Foo make() { return Foo(); }
void use(Foo& foo) { }
int main()
{
use(make()); // Fails, as discussed above
use(Foo() = make()); // Compiles
}
Thanks,
Ethan
---
[ 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 ] |
|
| Back to top |
|
 |
Guest
|
Posted: Thu Jul 27, 2006 7:32 pm Post subject: Re: reference to non-const temporary |
|
|
Ethan Eade wrote:
| Quote: | I'm curious -- why aren't temporaries allowed to be passed as non-const
references? It seems slightly arbitrary, since non-const methods can be
called on them anyway.
|
It is arbitrary. IIRC, the rule was added to the language because
programmers were getting unexpected results from code like:
void add_one( long& x ) { x = x + 1; }
int i = 1;
add_one( i );
assert( i == 2 );
At first glance, it's easy to imagine that add_one( i ) will operate on
i, but, of course, it doesn't -- it operates on a temporary, the result
of the implicit conversion from int to long.
It's possible to say, "Well, don't make that mistake." But I gather
that, in real life, programmers *did* make this mistake, often enough
that the "const rule" was added in order to catch it.
---
[ 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 ] |
|
| Back to top |
|
 |
Seungbeom Kim Guest
|
Posted: Fri Jul 28, 2006 1:40 am Post subject: Re: reference to non-const temporary |
|
|
Frederick Gotham wrote:
| Quote: | Ethan Eade posted:
I'm curious -- why aren't temporaries allowed to be passed as non-const
references?
If you pass either:
(1) non-const reference
(2) pointer to non-const
to a function, then that implies that the function is going to alter
something.
Logic dictates that you only alter something if there's a reason to.
If you pass a temporary, then any such alterations will be lost.
|
But there are times when we don't care.
What useful 'alterations' do you succeed to keep because you can't write
void process(std::istream&);
process(std::ifstream(filename));
but instead you have to write
void process(std::istream&);
std::ifstream tmp(filename);
process(tmp);
? Because you can't write
bool extract(std::istream& is, int& i) { return is >> i; }
std::string s("123"); int i;
extract(std::istringstream(s), i);
but instead you have to write
bool extract(std::istream& is, int& i) { return is >> i; }
std::string s("123"); int i;
std::istringstream is(s);
extract(is, i);
// "is" not needed any more
? (The gain is a pain in the neck, I think.)
Why does the language offer us "a nice safety feature" that we always
have to accept even though we may not want? Why does it force us to
resort to hacks such as "ostringstream().flush() << ..." instead of
plain, simple, and intuitive "ostringstream() << ..."?
As I have written several times in newsgroups, it does makes sense to
forbid bounding to a non-const reference a temporary created through
implicit conversion (as in
void incr(int& r) { r++; }
double d = 1;
incr(d);
), but not to forbid it for all temporaries, in particular explicitly
created ones such as foo().
Is anything going on to change this?
| Quote: | It seems slightly arbitrary, since non-const methods can be
called on them anyway.
But it still ensures that we don't discard alterations.
|
How?
struct foo { int x; void f() { ++x; } };
foo().f();
How does the language help you not to discard alterations on the
temporary foo()?
| Quote: | Surely such temporaries are fully constructed
objects. What's the rationale? It seems the restriction is trivially
circumvented using operator=():
struct Foo {};
Foo make() { return Foo(); }
void use(Foo& foo) { }
int main()
{
use(make()); // Fails, as discussed above
use(Foo() = make()); // Compiles
}
This I just plain don't understand. In the last line in "main", it appears
you're assigning to an R-value.
Since when can we assign to an R-value?
|
A long time ago, though I cannot tell exactly.
| Quote: | Furthermore, since when can this R-value then be passed by non-const
reference... ?
|
The return value of the assignment operator is an lvalue.
--
Seungbeom Kim
---
[ 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 ] |
|
| Back to top |
|
 |
Ethan Eade Guest
|
Posted: Fri Jul 28, 2006 9:10 am Post subject: Re: reference to non-const temporary |
|
|
johnchx2 (AT) yahoo (DOT) com wrote:
| Quote: | It is arbitrary. IIRC, the rule was added to the language because
programmers were getting unexpected results from code like:
void add_one( long& x ) { x = x + 1; }
int i = 1;
add_one( i );
assert( i == 2 );
It's possible to say, "Well, don't make that mistake." But I gather
that, in real life, programmers *did* make this mistake, often enough
that the "const rule" was added in order to catch it.
|
That makes sense. But surely the restriction can be limited to
temporaries created by implicit conversion.
As Seungbeom Kim points out above, the rule in its current form merely
encourages ugly use of methods that return a reference to the object:
struct Foo {
Foo& self() { return *this; }
};
Foo make();
void use(Foo& foo);
int main() {
use(make().self());
}
That seems silly and pointless. Or the following, which I consider even
worse:
struct Foo {};
template <class T> struct Ref {
T value;
Ref(T t) : value(t) {}
operator T& () { return value; }
};
....
use(Ref<Foo>(make()));
- Ethan
---
[ 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 ] |
|
| Back to top |
|
 |
Samee Zahur Guest
|
Posted: Fri Jul 28, 2006 5:27 pm Post subject: Re: reference to non-const temporary |
|
|
johnchx2 (AT) yahoo (DOT) com wrote:
| Quote: | Ethan Eade wrote:
I'm curious -- why aren't temporaries allowed to be passed as non-const
references? It seems slightly arbitrary, since non-const methods can be
called on them anyway.
It is arbitrary. IIRC, the rule was added to the language because
programmers were getting unexpected results from code like:
void add_one( long& x ) { x = x + 1; }
|
Actually, I've seen this topic come up on this group a number of times,
and this same rationale being posted a number of times. But this
problem can only occur when there is an implicit conversion going on.
Why not just disable implicit conversion whenever initializing a
non-const ref with a temporary? That way an int temporary could be
assigned to int& but not long&
This solution seems a lot cleaner ... but since its so obvious and yet
not implemented I guess there has to be a reason. But I am curious to
know what that is ... dont see it posted that often :(
Samee
---
[ 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 ] |
|
| Back to top |
|
 |
Greg Herlihy Guest
|
Posted: Sun Jul 30, 2006 6:00 am Post subject: Re: reference to non-const temporary |
|
|
Ethan Eade wrote:
| Quote: | johnchx2 (AT) yahoo (DOT) com wrote:
It is arbitrary. IIRC, the rule was added to the language because
programmers were getting unexpected results from code like:
void add_one( long& x ) { x = x + 1; }
int i = 1;
add_one( i );
assert( i == 2 );
It's possible to say, "Well, don't make that mistake." But I gather
that, in real life, programmers *did* make this mistake, often enough
that the "const rule" was added in order to catch it.
That makes sense. But surely the restriction can be limited to
temporaries created by implicit conversion.
As Seungbeom Kim points out above, the rule in its current form merely
encourages ugly use of methods that return a reference to the object:
struct Foo {
Foo& self() { return *this; }
};
Foo make();
void use(Foo& foo);
int main() {
use(make().self());
}
That seems silly and pointless.
|
The example program is somewhat contrived. What does the use() function
do exactly? There should be just one answer to that question. So either
use() should perform some operation for which foo serves as input (in
which case foo should be declared a const reference) or use() should
perform some operation upon its foo parameter (in which case passing a
temporary wouldn't make much sense).
In short there is no defect in the language illustrated by the sample
code, but merely a muddled interface.
Greg
---
[ 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 ] |
|
| Back to top |
|
 |
Dave Harris Guest
|
Posted: Sun Jul 30, 2006 9:08 pm Post subject: Re: reference to non-const temporary |
|
|
greghe (AT) pacbell (DOT) net (Greg Herlihy) wrote (abridged):
| Quote: | The example program is somewhat contrived. What does the use() function
do exactly? There should be just one answer to that question. So either
use() should perform some operation for which foo serves as input (in
which case foo should be declared a const reference) or use() should
perform some operation upon its foo parameter (in which case passing a
temporary wouldn't make much sense).
|
By that argument, it should not be possible to ignore function results,
either. There's not much moral difference between:
void inc_v1( long &x ) { ++x; }
and
long inc_v2( long x ) { return ++x; }
yet we are allowed to write:
int i = 0;
inc_v2( i );
And this is a good thing. Think of strcat(), for example, or printf(), or
any number of other functions whose result is frequently ignored. The
single-purpose purity you desire is an inconvenient burden in practice. If
ignoring results is OK when they are function returns, why not when they
are reference parameters?
In addition, non-const reference arguments are not just used to return
results. Sometimes they are used to provide the function with some
work-space. If the function created (and destroyed) the object itself, it
would incur overhead for each call that could be onerous eg if it is
called in a tight loop. If the caller creates the object outside the loop
and passes it in, the const of construction is only incurred once. In this
case the caller doesn't care what the final value of the object is, and
there's no reason why they shouldn't pass a temporary object.
-- Dave Harris, Nottingham, UK.
---
[ 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 ] |
|
| Back to top |
|
 |
Dave Harris Guest
|
Posted: Mon Jul 31, 2006 1:23 am Post subject: Re: reference to non-const temporary |
|
|
samee.zahur (AT) gmail (DOT) com (Samee Zahur) wrote (abridged):
| Quote: | void add_one( long& x ) { x = x + 1; }
Actually, I've seen this topic come up on this group a number of times,
and this same rationale being posted a number of times. But this
problem can only occur when there is an implicit conversion going on.
Why not just disable implicit conversion whenever initializing a
non-const ref with a temporary? That way an int temporary could be
assigned to int& but not long&
|
Yes, I'm pretty sure I've posted similar comments before. What seems to
have happened is that the gurus have instead pursued the path of providing
a new kind of reference that can bind to non-const temporaries, using the
"&&" syntax. Thus:
void add_one( long &&x ) { ++x; }
The advantage, as I understand it, is that with both overloads the
programmer /knows/ whether x is bound to a temporary or a variable. He or
she can use this knowledge to make the function more efficient - by not
bothering to fill in the return value, and/or reusing the object passed
for the function's own purposes instead.
The disadvantage, again as I understand it, is that it opens up the
implicit conversion issue again. In effect by using && references you are
saying you are prepared to live with the danger. Could any of the people
supporting the l-value reference proposal confirm whether this issue
remains?
-- Dave Harris, Nottingham, UK.
---
[ 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 ] |
|
| Back to top |
|
 |
Howard Hinnant Guest
|
Posted: Mon Jul 31, 2006 1:41 am Post subject: Re: reference to non-const temporary |
|
|
In article <eab335$4ks$1 (AT) news (DOT) Stanford.EDU>,
musiphil (AT) bawi (DOT) org (Seungbeom Kim) wrote:
| Quote: | Logic dictates that you only alter something if there's a reason to.
If you pass a temporary, then any such alterations will be lost.
But there are times when we don't care.
|
Right.
| Quote: | What useful 'alterations' do you succeed to keep because you can't write
|
<snip several example uses of rvalue streams>
| Quote: | ? (The gain is a pain in the neck, I think.)
|
<nod>
| Quote: | Is anything going on to change this?
|
Many people have been contributing to this over the past 5 years:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html
The language change was voted in favor of by the Evolution Working Group
in Apr 2005, and has been under review of the Core Working Group since
Oct 2005. It has not yet made it into the C++0X working draft:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2009.pdf
If accepted, this would allow:
void process(std::istream&&);
process(std::ifstream(filename));
N1690 (referenced from N2027) details more uses involving rvalue
streams, as well as other uses of the rvalue reference.
-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 ] |
|
| Back to top |
|
 |
Howard Hinnant Guest
|
Posted: Mon Jul 31, 2006 2:41 am Post subject: Re: reference to non-const temporary |
|
|
In article <memo.20060730194459.2336A (AT) brangdon (DOT) cix.compulink.co.uk>,
brangdon (AT) cix (DOT) co.uk (Dave Harris) wrote:
| Quote: | Yes, I'm pretty sure I've posted similar comments before. What seems to
have happened is that the gurus have instead pursued the path of providing
a new kind of reference that can bind to non-const temporaries, using the
"&&" syntax. Thus:
void add_one( long &&x ) { ++x; }
The advantage, as I understand it, is that with both overloads the
programmer /knows/ whether x is bound to a temporary or a variable. He or
she can use this knowledge to make the function more efficient - by not
bothering to fill in the return value, and/or reusing the object passed
for the function's own purposes instead.
The disadvantage, again as I understand it, is that it opens up the
implicit conversion issue again. In effect by using && references you are
saying you are prepared to live with the danger. Could any of the people
supporting the l-value reference proposal confirm whether this issue
remains?
|
Yes, the implicit conversion issue remains with &&. It is up to the
function designer to choose the correct type of reference. The rvalue
reference (&&) should not be viewed as a "fixed reference". Both the
lvalue reference (&) and rvalue reference (&&) have valuable use cases.
In the example "add_one" above, use of && is a poor choice since the
intent of this function is to modify the parameter, and that is the only
output.
Take an auto_ptr-like constructor as the counter example:
template <class T>
auto_ptr<T>::auto_ptr(auto_ptr&& p);
Here the "output" of the function is to construct a new auto_ptr. The
fact that this process modifies the argument is secondary, and not a
logical error if ignored. Thus here it makes sense to allow binding to
an rvalue (whereas it doesn't make sense if the argument modification is
the only visible effect).
Having both & and && in your tool box allows for a wide range of
powerful techniques, including the ability to disallow rvalue arguments,
or even *only* allow rvalue arguments, if that meets your interface
requirements.
For more info, see:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html
-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 ] |
|
| Back to top |
|
 |
James Dennett Guest
|
Posted: Mon Jul 31, 2006 9:10 am Post subject: Re: reference to non-const temporary |
|
|
Greg Herlihy wrote:
| Quote: | Ethan Eade wrote:
johnchx2 (AT) yahoo (DOT) com wrote:
It is arbitrary. IIRC, the rule was added to the language because
programmers were getting unexpected results from code like:
void add_one( long& x ) { x = x + 1; }
int i = 1;
add_one( i );
assert( i == 2 );
It's possible to say, "Well, don't make that mistake." But I gather
that, in real life, programmers *did* make this mistake, often enough
that the "const rule" was added in order to catch it.
That makes sense. But surely the restriction can be limited to
temporaries created by implicit conversion.
As Seungbeom Kim points out above, the rule in its current form merely
encourages ugly use of methods that return a reference to the object:
struct Foo {
Foo& self() { return *this; }
};
Foo make();
void use(Foo& foo);
int main() {
use(make().self());
}
That seems silly and pointless.
The example program is somewhat contrived. What does the use() function
do exactly? There should be just one answer to that question. So either
use() should perform some operation for which foo serves as input (in
which case foo should be declared a const reference) or use() should
perform some operation upon its foo parameter (in which case passing a
temporary wouldn't make much sense).
In short there is no defect in the language illustrated by the sample
code, but merely a muddled interface.
|
Not necessarily. A common example of this is using a stream
object; we can't use a const stream (as we can't write to such
a thing), and yet we're often not interested in the state of
the stream itself, but on its side-effects. In the context
of std::ostream, flush() is often used for self().
-- 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 ] |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|