 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Brian Clarkson Guest
|
Posted: Tue Jan 25, 2005 3:05 am Post subject: So a reference to temporary must be const? why? |
|
|
Hello.
I came across this problem while porting some code from vc++ to gcc.
From my shaky understanding of the ANSI C++ standard, temporaries are
guaranteed to stick around at least until right before execution of the
next line (or up until the semicolon). However, it seems that a
non-const reference to a temporary is forbidden. Isn' t this way too
strict?
I have distilled the issue to the following example:
****begin test.cpp****
#include <iostream>
using namespace std;
class vector {
public:
vector(int x_, int y_) : x(x_), y(y_) {}
vector(const vector& xx) : x(xx.x), y(xx.y) {}
vector& operator=(const vector& xx) { x = xx.x; y = xx.y; return
*this; }
friend vector operator+(const vector& a, const vector& b);
public:
int x, y;
};
vector operator+(const vector& a, const vector& b) {
// vector tmp(a.x + b.x, a.y + b.y);
// return tmp;
return vector(a.x + b.x, a.y + b.y);
}
void f(vector& v)
{
cout << "vector = (" << v.x << ", " << v.y << ")" << endl;
}
int main()
{
vector a(1, 2);
vector b(2, 3);
f(a+b); // this line generates an error
return 0;
}
****end test.cpp****
Which when compiled gives the following output:
g++ test.cpp
test.cpp: In function `int main()':
test.cpp:32: error: could not convert `operator+(const vector&, const
vector&)((&b))' to `vector&'
test.cpp:23: error: in passing argument 1 of `void f(vector&)'
If f() is defined as f(const vector&) then this example compiles, but
it seems to me that operating on a reference to the temporary that is
generated from (a+b) should be safe since we are finished with it
before the semicolon.
Is there a better way to do this? (i.e. no explicit temporaries and no
unnecessary copies)
Thanks in advance.
Brian
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
jacobsson@gmail.com Guest
|
Posted: Tue Jan 25, 2005 3:23 pm Post subject: Re: So a reference to temporary must be const? why? |
|
|
Temporary objects are lvalues in VC7, i.e., they can be passed as
non-const references. In GCC, temporary objects are rvalues and can
only be passed as const references:
class X;
void foo(X& x)
{
x.y = 2;
}
void bar()
{
// BAD: temporary X object is not an lvalue
foo(X(10));
}
daniel
Brian Clarkson wrote:
| Quote: | Hello.
I came across this problem while porting some code from vc++ to gcc.
From my shaky understanding of the ANSI C++ standard, temporaries
are
guaranteed to stick around at least until right before execution of
the
next line (or up until the semicolon). However, it seems that a
non-const reference to a temporary is forbidden. Isn' t this way too
strict?
I have distilled the issue to the following example:
****begin test.cpp****
#include
using namespace std;
class vector {
public:
vector(int x_, int y_) : x(x_), y(y_) {}
vector(const vector& xx) : x(xx.x), y(xx.y) {}
vector& operator=(const vector& xx) { x = xx.x; y = xx.y; return
*this; }
friend vector operator+(const vector& a, const vector& b);
public:
int x, y;
};
vector operator+(const vector& a, const vector& b) {
// vector tmp(a.x + b.x, a.y + b.y);
// return tmp;
return vector(a.x + b.x, a.y + b.y);
}
void f(vector& v)
{
cout << "vector = (" << v.x << ", " << v.y << ")" << endl;
}
int main()
{
vector a(1, 2);
vector b(2, 3);
f(a+b); // this line generates an error
return 0;
}
****end test.cpp****
Which when compiled gives the following output:
g++ test.cpp
test.cpp: In function `int main()':
test.cpp:32: error: could not convert `operator+(const vector&, const
vector&)((&b))' to `vector&'
test.cpp:23: error: in passing argument 1 of `void f(vector&)'
If f() is defined as f(const vector&) then this example compiles, but
it seems to me that operating on a reference to the temporary that is
generated from (a+b) should be safe since we are finished with it
before the semicolon.
Is there a better way to do this? (i.e. no explicit temporaries and
no
unnecessary copies)
Thanks in advance.
Brian
---
[ 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.jamesd.demon.co.uk/csc/faq.html
] |
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
msalters Guest
|
Posted: Tue Jan 25, 2005 6:00 pm Post subject: Re: So a reference to temporary must be const? why? |
|
|
Brian Clarkson wrote:
| Quote: | I came across this problem while porting some code from vc++ to gcc.
From my shaky understanding of the ANSI C++ standard, temporaries
are
guaranteed to stick around at least until right before execution of
the
next line (or up until the semicolon). However, it seems that a
non-const reference to a temporary is forbidden. Isn' t this way too
strict?
|
"next line" doesn't really exist in C++, only the preprocessor
cares about lines. "The next semicolon" is a nice approximation,
except of course that quoted or commented doesn't count etc.
Binding references to non-temporaries was tried back in the eighties,
when C++ was still very much a research project. It turned out to
be a source of bugs. Basically, references were used to modify
these temporaries, and the resulting modifications were then lost
once the temporary was destroyed.
| Quote: | I have distilled the issue to the following example:
#include
using namespace std;
class vector {
public:
vector(int x_, int y_) : x(x_), y(y_) {}
public:
int x, y;
};
vector operator+(const vector& a, const vector& b) {
return vector(a.x + b.x, a.y + b.y);
}
void f(vector& v)
{
cout << "vector = (" << v.x << ", " << v.y << ")" << endl;
}
|
Obviously, f doesn't need to change v, so you just missed a const here.
| Quote: | int main()
{
vector a(1, 2);
vector b(2, 3);
f(a+b); // this line generates an error
return 0;
}
If f() is defined as f(const vector&) then this example compiles, but
it seems to me that operating on a reference to the temporary that is
generated from (a+b) should be safe since we are finished with it
before the semicolon.
|
No, it's not safe, because any modification by f will be lost. There's
no place to store it. But if f doesn't modify (a+b), it can take its
argument by const reference. You must choose. Mutating functions just
don't work with temporaries.
Regards,
Michiel Salters
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Ian McCulloch Guest
|
Posted: Tue Jan 25, 2005 6:54 pm Post subject: Re: So a reference to temporary must be const? why? |
|
|
msalters wrote:
| Quote: | No, it's not safe, because any modification by f will be lost. There's
no place to store it. But if f doesn't modify (a+b), it can take its
argument by const reference. You must choose. Mutating functions just
don't work with temporaries.
|
Except when the temporary is a proxy. ;)
But maybe rvalue references
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html ) will
fix that case?
Cheers,
Ian McCulloch
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Howard Hinnant Guest
|
Posted: Tue Jan 25, 2005 10:36 pm Post subject: Re: So a reference to temporary must be const? why? |
|
|
In article <35niefF312m05U1 (AT) news (DOT) dfncis.de>,
[email]ianmcc (AT) physik (DOT) rwth-aachen.de[/email] (Ian McCulloch) wrote:
| Quote: | msalters wrote:
No, it's not safe, because any modification by f will be lost. There's
no place to store it. But if f doesn't modify (a+b), it can take its
argument by const reference. You must choose. Mutating functions just
don't work with temporaries.
Except when the temporary is a proxy. ;)
But maybe rvalue references
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html ) will
fix that case?
|
Half way. The rvalue reference allows the function author to say: let
temporaries bind to this non-const reference (perhaps to allow
proxies?). However if you're the proxy author, not the function author,
then you have no say in the matter.
What is needed is a way for the proxy author to say: this temporary is
special, let it always bind to a non-const (lvalue) reference. Possible
syntax for that might be:
struct my_proxy
{
operator my_proxy&() {return *this;}
};
-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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Wed Jan 26, 2005 5:05 am Post subject: Re: So a reference to temporary must be const? why? |
|
|
Brian Clarkson wrote:
| Quote: | I came across this problem while porting some code from vc++
to gcc. From my shaky understanding of the ANSI C++ standard,
temporaries are guaranteed to stick around at least until
right before execution of the next line (or up until the
semicolon). However, it seems that a non-const reference to a
temporary is forbidden. Isn' t this way too strict?
|
Maybe.
The rule wasn't in the earliest versions of C++ that I knew. It
was introduced because allowing binding a temporary to a
non-const turned out to be excessively error-prone; e.g:
| Quote: | void
incr( int& i )
{
++ i ;
}
void
f()
{
unsigned i = 0 ;
incr( i ) ;
// i sitll equal 0 !
}
|
The real problem, of course, is that temporaries are often
invisible. Presumably, in f() above, the user wanted to modify
i when he called incr. Because of the implicit type conversion,
however, he only modified a temporary, and the results of the
modification disappeared at the end of the full expression.
The rule was introduced to solve a real problem. Whatever else,
expressions like "incr( i )" above must be illegal. There is
some argument, however, that binding an explicit temporary to an
lvalue should be allowed; that only the results of an implicit
type conversion should be banned. I don't think that there is a
proposal in this sense before the committee, however.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
John Nagle Guest
|
Posted: Wed Jan 26, 2005 5:06 am Post subject: Re: So a reference to temporary must be const? why? |
|
|
Ian McCulloch wrote:
| Quote: | msalters wrote:
No, it's not safe, because any modification by f will be lost. There's
no place to store it. But if f doesn't modify (a+b), it can take its
argument by const reference. You must choose. Mutating functions just
don't work with temporaries.
|
Arguably this goes against a general design principle of C++,
"You're allowed to do it even it it's stupid".
One could argue that it should be allowed to write
(a + b) = c + d;
on the grounds that it is possible to define a, b,
and the relevant "operator+" in such a way that this
does something marginally useful.
For example, consider
bool errout; int a,b,c;
(errout ? cerr : cout) << a << b << c;
The ability to use the "?" operator in an LHS would be
useful.
I'm not seriously proposing this,. But this is where the
non-const reference proposals ("&&", and all that) lead.
John Nagle
Animats
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
akrylik Guest
|
Posted: Wed Jan 26, 2005 6:23 am Post subject: Re: So a reference to temporary must be const? why? |
|
|
Proxy! That's exactly what I want to use the temporary for, I just
didn't know that is what it's called. (FYI, I want to be able to write
expressions using temporary "views" of vectors, like in matlab: x(2:4)
= y(1:5)+5 and so on.)
So here is something weird (to me at least). I tried Howard's
suggestion and added a type conversion operator to the vector example
like this:
class vector {
public:
vector(int x_, int y_) : x(x_), y(y_) {}
vector(const vector& xx) : x(xx.x), y(xx.y) {}
vector& operator=(const vector& xx) { x = xx.x; y = xx.y; return
*this; }
operator vector&(){return *this;}
int x, y;
};
And compiling gives the following result:
test.cpp:11: warning: conversion to a reference to the same type will
never use
a type conversion operator
But its just a warning and the code runs. Is this just badly worded
warning?
(BTW, thanks everyone for your responses.)
-Brian
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Ian McCulloch Guest
|
Posted: Wed Jan 26, 2005 7:09 am Post subject: Re: So a reference to temporary must be const? why? |
|
|
John Nagle wrote:
| Quote: | Ian McCulloch wrote:
msalters wrote:
No, it's not safe, because any modification by f will be lost. There's
no place to store it. But if f doesn't modify (a+b), it can take its
argument by const reference. You must choose. Mutating functions just
don't work with temporaries.
Arguably this goes against a general design principle of C++,
"You're allowed to do it even it it's stupid".
One could argue that it should be allowed to write
(a + b) = c + d;
on the grounds that it is possible to define a, b,
and the relevant "operator+" in such a way that this
does something marginally useful.
|
? You don't need to argue for it, this is already possible. You can't bind
a temporary to a non-const reference, but you *can* call a non-const
operator with one (such as the assignment operator):
// nothing out of the ordinary here
struct foo
{
foo(double x) : x_(x) {}
foo& operator=(foo const& n) { x_ = n.x_; return *this; }
double x_;
};
// nor here
foo operator+(foo const& a, foo const& b)
{
return foo(a.x_ + b.x_);
}
typedef double foo;
int main()
{
foo a(1), b(2), c(3), d(4);
(a + b) = c + d; // hmm
}
| Quote: |
For example, consider
bool errout; int a,b,c;
(errout ? cerr : cout) << a << b << c;
The ability to use the "?" operator in an LHS would be
useful.
|
This used to be possible, sometimes, when iostream classes had operator<< as
a member function.
| Quote: | I'm not seriously proposing this,. But this is where the
non-const reference proposals ("&&", and all that) lead.
|
I'm not sure that && makes it any worse, and there are certainly places
where && makes a big improvement in const-safety. For proxies that follow
the logical constness of their pointee (so a const proxy is rougly the same
as a proxy to a const), the copy ctor ought to take its argument by
non-const reference, otherwise it is possible to constuct a non-const proxy
out of a const proxy. But this is ordinarily not possible. But a copy
ctor of foo::foo(foo&&) would do the trick, AFAICT.
Cheers,
Ian McCulloch
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Motti Lanzkron Guest
|
Posted: Wed Jan 26, 2005 7:11 am Post subject: Re: So a reference to temporary must be const? why? |
|
|
Howard Hinnant wrote:
| Quote: | In article <35niefF312m05U1 (AT) news (DOT) dfncis.de>,
[email]ianmcc (AT) physik (DOT) rwth-aachen.de[/email] (Ian McCulloch) wrote:
msalters wrote:
No, it's not safe, because any modification by f will be lost. There's
no place to store it. But if f doesn't modify (a+b), it can take its
argument by const reference. You must choose. Mutating functions just
don't work with temporaries.
Except when the temporary is a proxy. ;)
But maybe rvalue references
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html ) will
fix that case?
Half way. The rvalue reference allows the function author to say: let
temporaries bind to this non-const reference (perhaps to allow
proxies?). However if you're the proxy author, not the function author,
then you have no say in the matter.
What is needed is a way for the proxy author to say: this temporary is
special, let it always bind to a non-const (lvalue) reference. Possible
syntax for that might be:
struct my_proxy
{
operator my_proxy&() {return *this;}
};
|
That's a very neat idea. Unfortunately Comeau says:
"ComeauTest.c", line 3: warning: "my_proxy::operator my_proxy &()"
will not be
called for implicit or explicit conversions
operator my_proxy&() {return *this;}
^
Section 12.3.2/1 [thanks Ben Hutchings for an old post regarding
operator void()] says:
... A conversion function is never used to convert a (possibly
cv-qualified) object to the (possibly cv-qualified) same object type
(or a reference to it), to a (possibly cv-qualified) base class of
that type (or a reference to it), or to (possibly cv-qualified)
void.[103]
[103] Even though never directly called to perform a conversion such
conversion functions can be declared and can potentially be reached
through a call to a virtual conversion function in a base class.
I'm not sure why this is disallowed (especially in the void case).
I took the foot-note to mean that this would be OK;
struct my_proxy;
struct my_proxy_base {
virtual operator my_proxy&() = 0;
};
struct my_proxy : my_proxy_base
{
virtual operator my_proxy&() {return *this;}
};
void test(my_proxy&);
test(my_proxy());
But (at least according to Comeau) the following conversion chain
isn't considered:
rvalue my_proxy -> rvalue my_proxy_base
rvalue my_proxy_base -> operator my_proxy&
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Ben Hutchings Guest
|
Posted: Wed Jan 26, 2005 4:00 pm Post subject: Re: So a reference to temporary must be const? why? |
|
|
John Nagle wrote:
<snip>
| Quote: | For example, consider
bool errout; int a,b,c;
(errout ? cerr : cout) << a << b << c;
The ability to use the "?" operator in an LHS would be
useful.
snip |
It already exists; if the second and third operands of the conditional
operator are lvalues of the same type, as cerr and cout are, then so
is its result.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Ian McCulloch Guest
|
Posted: Wed Jan 26, 2005 4:00 pm Post subject: Re: So a reference to temporary must be const? why? |
|
|
Howard Hinnant wrote:
| Quote: | In article <35niefF312m05U1 (AT) news (DOT) dfncis.de>,
[email]ianmcc (AT) physik (DOT) rwth-aachen.de[/email] (Ian McCulloch) wrote:
msalters wrote:
No, it's not safe, because any modification by f will be lost. There's
no place to store it. But if f doesn't modify (a+b), it can take its
argument by const reference. You must choose. Mutating functions just
don't work with temporaries.
Except when the temporary is a proxy. ;)
But maybe rvalue references
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html )
will fix that case?
Half way. The rvalue reference allows the function author to say: let
temporaries bind to this non-const reference (perhaps to allow
proxies?). However if you're the proxy author, not the function author,
then you have no say in the matter.
What is needed is a way for the proxy author to say: this temporary is
special, let it always bind to a non-const (lvalue) reference. Possible
syntax for that might be:
struct my_proxy
{
operator my_proxy&() {return *this;}
};
|
Interesting. I had actually given up on the idea of totally transparent
proxying, because if the function author does want to do something with the
proxy beyond the lifetime of the temporary proxy, then AFAICT it needs
special behaviour anyway. eg.
template <typename ValueOrProxy>
struct UniversalProxy
{
UniveralProxy(ValueOrProxy& x) : x_(x) {}
operator ValueOrProxy&() { return x_; }
operator ValueOrProxy const&() { return x_; }
// what type does x_ have? Assume is_proxy is available
typedef typename boost::mpl::if_<
is_proxy
ValueOrProxy, ValueOrProxy&
ref_type x_;
};
// this really ought to work for rvalue-references,
// but only if the rvalue is a proxy.
template <typename T>
UniversalProxy<T> make_proxy(T& x)
{
return UniversalProxy<T>(x);
}
// nothing can be done to make this safer?
template <typename T>
UniversalProxy<T const> make_proxy(T const& x)
{
return UniversalProxy<T const>(x);
}
With the operator& solution, the non-const version of make_proxy would work
properly, so that is a big improvement. But is_proxy is needed in the
implementation of UniversalProxy anyway, I think. With rvalue references,
you need enable_if on is_proxy to avoid taking an rvalue reference of a
value type, which adds a lot of syntax.
Anyway, either solution is better than the current version, which can
violate const-correctness:
template <typename T>
typename boost::enable_if<is_proxy::type
make_proxy(T const& x)
{
return UniversalProxy<T>(const_cast<T&>(x));
}
Is there a better way of specifying the ref_type in UniversalProxy?
Cheers,
Ian McCulloch
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
msalters Guest
|
Posted: Fri Jan 28, 2005 5:59 pm Post subject: Re: So a reference to temporary must be const? why? |
|
|
Ben Hutchings wrote:
| Quote: | John Nagle wrote:
snip
For example, consider
bool errout; int a,b,c;
(errout ? cerr : cout) << a << b << c;
The ability to use the "?" operator in an LHS would be
useful.
snip
It already exists; if the second and third operands of the
conditional
operator are lvalues of the same type, as cerr and cout are, then so
is its result.
|
and for non-builtins you can always do
/**/ bool errout; T a,b,c;
/**/ ((errout ? cerr : cout).flush()) << a << b << c;
( except where prohibited by coding standards or common sense )
Regards,
Michiel Salters
---
[ 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.jamesd.demon.co.uk/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
|
|