 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Adrian Sandor Guest
|
Posted: Fri Apr 16, 2004 6:10 am Post subject: const objects |
|
|
Hello, please take a look at the following program:
//--------8<---------
#include
struct test
{
int x;
explicit test(int y) (y){}
test&operator+=(int y)
{
x+=y;
return *this;
}
};
void f(test&x)
{
std::cout<
}
int main()
{
f(test(3)); //doesn't compile because test(3) is a const ref.
f(test(3)+=5); //compiles fine (?!)
}
//-------->8---------
I'm using gcc 3.2 on Windows (mingw).
I also tested the code at http://www.dinkumware.com/exam and it
compiles fine with VC++ but has the same behaviour (as commented
above) with EDG.
What is the correct behaviour?
Is it allowed for a temp. object to become a non-const ref (either
directly or through a non-const member function, but without any cast)
?
Adrian
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Michiel Salters Guest
|
Posted: Fri Apr 16, 2004 6:39 pm Post subject: Re: const objects |
|
|
[email]aditsu (AT) yahoo (DOT) com[/email] (Adrian Sandor) wrote in message news:<8ecf8e03.0404142051.27cda079 (AT) posting (DOT) google.com>...
| Quote: | Hello, please take a look at the following program:
//--------8<---------
snipped a bit
struct test
{
explicit test(int) { }
test&operator+=(int )
{
return *this;
}
};
void f(test&x) { }
int main()
{
f(test(3)); //doesn't compile because test(3) is a const ref.
f(test(3)+=5); //compiles fine (?!)
}
//-------->8---------
What is the correct behaviour?
Is it allowed for a temp. object to become a non-const ref (either
directly or through a non-const member function, but without any cast)
|
What you see is the difference in initializatio between the implicit
'this' parameter of operator+= and the explicit 'x' paramater of f.
This difference is covered by 13.3.1/5 :
| Quote: |
During overload resolution, the implied object argument is
indistinguishable from other arguments. The implicit object parameter,
however, retains its identity since conversions on the corresponding
argument shall obey these additional rules:
— no temporary object can be introduced to hold the argument
for the implicit object parameter;
— no user-defined conversions can be applied to achieve a type
match with it; and
— even if the implicit object parameter is not const-qualified,
an can be bound to the parameter as long as in
all other respects the temporary can be converted to the type
of the implicit object parameter.
|
The last sentence applies here. Your rvalue temporary is test(5),
and it can bind to the implicit object parameter of
test::operator+=( )
It cannot bind to the test&x argument of f, because f() is not a
member of test.
Regards,
Michiel Salters
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
John Potter Guest
|
Posted: Sat Apr 17, 2004 6:10 am Post subject: Re: const objects |
|
|
On 16 Apr 2004 02:10:03 -0400, [email]aditsu (AT) yahoo (DOT) com[/email] (Adrian Sandor) wrote:
| Quote: | void f(test&x)
{
std::cout<
}
int main()
{
f(test(3)); //doesn't compile because test(3) is a const ref.
|
No. test(3) is an rvalue not any kind of ref which would be an lvalue.
f(test(42) = test(3)); // compiles fine :)
| Quote: | f(test(3)+=5); //compiles fine (?!)
}
I'm using gcc 3.2 on Windows (mingw).
I also tested the code at http://www.dinkumware.com/exam and it
compiles fine with VC++ but has the same behaviour (as commented
above) with EDG.
What is the correct behaviour?
Is it allowed for a temp. object
|
Make that an rvalue.
| Quote: | to become a non-const ref (either
directly
|
No. The error reported by gcc and edg is required.
| Quote: | or through a non-const member function, but without any cast)
?
|
Yes.
The standard rvalue to lvalue conversion. Yes, a non-const member may
be called on an rvalue. Operator= is a non-const member which returns
an lvalue.
John
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Dhruv Matani Guest
|
Posted: Sat Apr 17, 2004 6:15 am Post subject: Re: const objects |
|
|
On Fri, 16 Apr 2004 02:10:03 -0400, Adrian Sandor wrote:
| Quote: | Hello, please take a look at the following program:
//--------8<---------
#include
struct test
{
int x;
explicit test(int y) (y){}
test&operator+=(int y)
{
x+=y;
return *this;
}
};
void f(test&x)
{
std::cout<
}
int main()
{
f(test(3)); //doesn't compile because test(3) is a const ref.
|
No. test(3) is a temporary, and temoraries can not be bound to non-const
refs.
| Quote: | f(test(3)+=5); //compiles fine (?!)
|
Yes. test(3)+=5 returns test&, which is accepted happily by f();
| Quote: | }
//-------->8---------
I'm using gcc 3.2 on Windows (mingw).
I also tested the code at http://www.dinkumware.com/exam and it
compiles fine with VC++ but has the same behaviour (as commented
above) with EDG.
What is the correct behaviour?
|
gcc and EDG.
| Quote: | Is it allowed for a temp. object to become a non-const ref (either
directly or through a non-const member function, but without any cast)
?
|
Yes, as you have demonstrated.
--
Regards,
-Dhruv.
Proud to be a Vegetarian.
http://www.vegetarianstarterkit.com/
http://www.vegkids.com/vegkids/index.html
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Jake Montgomery Guest
|
Posted: Sat Apr 17, 2004 10:05 pm Post subject: Re: const objects |
|
|
Michiel Salters wrote:
| Quote: | aditsu (AT) yahoo (DOT) com (Adrian Sandor) wrote in message news:<8ecf8e03.0404142051.27cda079 (AT) posting (DOT) google.com>...
Hello, please take a look at the following program:
//--------8<---------
snipped a bit
struct test
{
explicit test(int) { }
test&operator+=(int )
{
return *this;
}
};
void f(test&x) { }
int main()
{
f(test(3)); //doesn't compile because test(3) is a const ref.
f(test(3)+=5); //compiles fine (?!)
}
//-------->8---------
What you see is the difference in initializatio between the implicit
'this' parameter of operator+= and the explicit 'x' paramater of f.
This difference is covered by 13.3.1/5 :
| Quote: |
During overload resolution, the implied object argument is
indistinguishable from other arguments. The implicit object parameter,
however, retains its identity since conversions on the corresponding
argument shall obey these additional rules:
— no temporary object can be introduced to hold the argument
for the implicit object parameter;
— no user-defined conversions can be applied to achieve a type
match with it; and
— even if the implicit object parameter is not const-qualified,
an can be bound to the parameter as long as in
all other respects the temporary can be converted to the type
of the implicit object parameter.
|
The last sentence applies here. Your rvalue temporary is test(5),
and it can bind to the implicit object parameter of
test::operator+=( )
It cannot bind to the test&x argument of f, because f() is not a
member of test.
|
Now I am confused. Are you saying that the following code is illegal?
Or perhaps I missed some subtlety of your comments? (I use VC7.1 and it
compiles fine.) If so, I have been writing a lot of illegal code.
struct A
{
A(int y) (y){}
int x;
};
void f(A&a){}
int main()
{
f(A(7);
return 0;
}
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ben Hutchings Guest
|
Posted: Sat Apr 17, 2004 10:24 pm Post subject: Re: const objects |
|
|
Adrian Sandor wrote:
| Quote: | Hello, please take a look at the following program:
//--------8<---------
#include
struct test
{
int x;
explicit test(int y) (y){}
test&operator+=(int y)
{
x+=y;
return *this;
}
};
void f(test&x)
{
std::cout<
}
int main()
{
f(test(3)); //doesn't compile because test(3) is a const ref.
f(test(3)+=5); //compiles fine (?!)
}
//-------->8---------
I'm using gcc 3.2 on Windows (mingw).
I also tested the code at http://www.dinkumware.com/exam and it
compiles fine with VC++ but has the same behaviour (as commented
above) with EDG.
What is the correct behaviour?
|
The behaviour of GCC and EDG is correct.
| Quote: | Is it allowed for a temp. object to become a non-const ref (either
directly or through a non-const member function, but without any cast)
?
|
Only through a member function. Yes, I know this is weird.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
John Potter Guest
|
Posted: Sun Apr 18, 2004 12:38 am Post subject: Re: const objects |
|
|
On 17 Apr 2004 18:05:45 -0400, Jake Montgomery <jacobmdrop (AT) yahoo (DOT) com>
wrote:
| Quote: | Now I am confused. Are you saying that the following code is illegal?
|
It is ill-formed, diagnostic required.
| Quote: | Or perhaps I missed some subtlety of your comments? (I use VC7.1 and it
compiles fine.)
|
An extension for a rule which was changed long ago.
| Quote: | If so, I have been writing a lot of illegal code.
|
Our tools do trick us.
| Quote: | struct A
{
A(int y) (y){}
int x;
};
void f(A&a){}
int main()
{
f(A(7);
|
I assume the code which compiled had another ')'.
A message from gcc-3.2:
junk2.cpp: In function `int main()':
junk2.cpp:11: could not convert `A(7)' to `A&'
junk2.cpp:7: in passing argument 1 of `void f(A&)'
Or, maybe you prefer Comeau:
"ComeauTest.c", line 11: error: initial value of reference to non-const
must be an lvalue
f(A(7));
^
John
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Adrian Sandor Guest
|
Posted: Mon Apr 19, 2004 9:49 am Post subject: Re: const objects |
|
|
Thanks everyone for the answers.
Well, if this is the case, then I can abuse this feature by adding the
following function to any class:
class xyz
{
//....
//public section here
xyz& ref()
{
return *this;
}
};
Then I can call any function that requires a non-const reference (and
even modifies the object) like this: f(xyz(blah, blah).ref()). If the
compiler is smart, it will optimize away the call to ref and will just
pass the reference.
What do you think about this?
Adrian
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Dave Moore Guest
|
Posted: Tue Apr 20, 2004 10:30 am Post subject: Re: const objects |
|
|
[email]aditsu (AT) yahoo (DOT) com[/email] (Adrian Sandor) wrote in message news:<8ecf8e03.0404182132.688c06c2 (AT) posting (DOT) google.com>...
| Quote: | Thanks everyone for the answers.
Well, if this is the case, then I can abuse this feature by adding the
following function to any class:
class xyz
{
//....
//public section here
xyz& ref()
{
return *this;
}
};
You can give yourself a nasty shock by sticking a fork in a light |
socket, but that doesn't mean it is a good idea 8*). You seem to be
missing the point that there is a good reason that a temporary object
cannot be bound to a non-const reference ... namely that the object
will die as soon as it goes out of scope. In the case of using a
temporary to initialize a reference, this occurs immediately after the
initialization expression is completed. So, when the reference is a
function argument, the destruction of the temporary actually occurs
*before* the function body of is executed.
| Quote: | Then I can call any function that requires a non-const reference (and
even modifies the object) like this: f(xyz(blah, blah).ref()).
|
AFAICT, your example is equivalent to:
xyz foo(blah,blah);
xyz& bar=foo; // perfectly legal initialization of xyz reference
foo.~xyz(); // explicit call of the destructor
f(bar); // still valid as far as the compiler is concerned, but
clearly not
// a good idea
| Quote: | If the compiler is smart, it will optimize away the call to ref and will
just pass the reference.
What do you think about this?
|
Guess 8*)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Tue Apr 20, 2004 9:48 pm Post subject: Re: const objects |
|
|
[email]aditsu (AT) yahoo (DOT) com[/email] (Adrian Sandor) wrote in message
news:<8ecf8e03.0404182132.688c06c2 (AT) posting (DOT) google.com>...
| Quote: | Well, if this is the case, then I can abuse this feature by adding the
following function to any class:
class xyz
{
//....
//public section here
xyz& ref()
{
return *this;
}
};
Then I can call any function that requires a non-const reference (and
even modifies the object) like this: f(xyz(blah, blah).ref()). If the
compiler is smart, it will optimize away the call to ref and will just
pass the reference.
What do you think about this?
|
It's a well known technique. In the classical iostream, the operator<<
for a char const* was a member, and I regularly used something like:
message( ostrstream() << "" << myThingy ) ;
If myThingy had a user defined type, of course, its operator<< wasn't a
member, and "ostream() << myThingy" would have been illegal.
In the standard iostream, the operator<< for char const* is not a member
(why they changed it, I don't know), so you have to find another
alternative; John Potter suggests:
message( ostringstream().flush() << myThingy ) ;
which is fine except for the name (flush() on a stringstream is a
no-op). I've since moved on to wrapper classes myself; this isn't the
only reason (the type checking is better too), but it also has the
advantage that all of the << operators are members, thanks to template
member functions.
--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Risto Lankinen Guest
|
Posted: Tue Apr 20, 2004 10:22 pm Post subject: Re: const objects |
|
|
"Dave Moore" <dtmoore (AT) rijnh (DOT) nl> wrote
| Quote: | So, when the reference is a
function argument, the destruction of the temporary actually occurs
*before* the function body of is executed.
|
Huh?!? This is certainly not true. The temporary will
be automatically destroyed, but only after the function
returns. If what you write was indeed true, then how
can temporaries be used as arguments at all (including
const references)?
What you may be thinking of is that if the function body
modifies the reference argument (possible only for non-
consts), then the resultant changes will be destroyed
without any chance of retrieval by the caller. This is
prevented with const references, not because they're
handled differently (since they're not), but because the
issue goes away as a const reference cannot be modified.
| Quote: | AFAICT, your example is equivalent to:
xyz foo(blah,blah);
xyz& bar=foo; // perfectly legal initialization of xyz reference
|
/* I have corrected the order of the following two lines: */
| Quote: | f(bar);
foo.~xyz(); // explicit call of the destructor
|
- Risto -
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Teh (tî'pô) Guest
|
Posted: Tue Apr 20, 2004 10:39 pm Post subject: Re: const objects |
|
|
Dave Moore proclaimed:
| Quote: | aditsu (AT) yahoo (DOT) com (Adrian Sandor) wrote in message news:<8ecf8e03.0404182132.688c06c2 (AT) posting (DOT) google.com>...
Thanks everyone for the answers.
Well, if this is the case, then I can abuse this feature by adding the
following function to any class:
class xyz
{
//....
//public section here
xyz& ref()
{
return *this;
}
};
You can give yourself a nasty shock by sticking a fork in a light
socket, but that doesn't mean it is a good idea 8*). You seem to be
missing the point that there is a good reason that a temporary object
cannot be bound to a non-const reference ... namely that the object
will die as soon as it goes out of scope. In the case of using a
temporary to initialize a reference, this occurs immediately after the
initialization expression is completed. So, when the reference is a
function argument, the destruction of the temporary actually occurs
*before* the function body of is executed.
|
Is that so? I thought that a temporary's scope is extended to that of
the const reference it's bound to. Both my compilers agree with me.
Anyway Adrian's solution is a bit redundant, it requires the ability
to be able to change the class while the same effect can be had for
any type.
For example:
struct X { };
template <typename T>
const T& cref(const T& t) { return t; }
void foo(X& x) { }
void foo(int& i) { i = 42; }
int main()
{
foo(const_cast<X&>(cref(X())));
foo(const_cast<int&>(cref(8+0))); // Not an emoticon ;o)
}
I suppose this could be useful when you have a function that takes a
reference as an "out param" which you don't care about and you don't
want to declare a dummy named variable.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ian McCulloch Guest
|
Posted: Tue Apr 20, 2004 10:40 pm Post subject: Re: const objects |
|
|
Dave Moore wrote:
| Quote: | aditsu (AT) yahoo (DOT) com (Adrian Sandor) wrote in message
news:<8ecf8e03.0404182132.688c06c2 (AT) posting (DOT) google.com>...
Thanks everyone for the answers.
Well, if this is the case, then I can abuse this feature by adding the
following function to any class:
class xyz
{
//....
//public section here
xyz& ref()
{
return *this;
}
};
You can give yourself a nasty shock by sticking a fork in a light
socket, but that doesn't mean it is a good idea 8*). You seem to be
missing the point that there is a good reason that a temporary object
cannot be bound to a non-const reference ... namely that the object
will die as soon as it goes out of scope. In the case of using a
temporary to initialize a reference, this occurs immediately after the
initialization expression is completed. So, when the reference is a
function argument, the destruction of the temporary actually occurs
*before* the function body of is executed.
|
Sorry if I have misunderstood your post here, but is that really true? I
thought the destruction of the temporary occurred after the *full
expression* in which it ocurred. Otherwise using a tempoary to initialize
a const reference would fail too, but this is common practice:
int foo();
void f(int const&);
f(foo()); // tempoary is destroyed before f is called? surely not!
Cheers,
Ian McCulloch
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Jake Montgomery Guest
|
Posted: Tue Apr 20, 2004 11:29 pm Post subject: Re: const objects |
|
|
Dave Moore wrote:
| Quote: | aditsu (AT) yahoo (DOT) com (Adrian Sandor) wrote in message news:<8ecf8e03.0404182132.688c06c2 (AT) posting (DOT) google.com>...
Thanks everyone for the answers.
Well, if this is the case, then I can abuse this feature by adding the
following function to any class:
class xyz
{
//....
//public section here
xyz& ref()
{
return *this;
}
};
You can give yourself a nasty shock by sticking a fork in a light
socket, but that doesn't mean it is a good idea 8*). You seem to be
missing the point that there is a good reason that a temporary object
cannot be bound to a non-const reference ... namely that the object
will die as soon as it goes out of scope. In the case of using a
temporary to initialize a reference, this occurs immediately after the
initialization expression is completed. So, when the reference is a
function argument, the destruction of the temporary actually occurs
*before* the function body of is executed.
Then I can call any function that requires a non-const reference (and
even modifies the object) like this: f(xyz(blah, blah).ref()).
AFAICT, your example is equivalent to:
xyz foo(blah,blah);
xyz& bar=foo; // perfectly legal initialization of xyz reference
foo.~xyz(); // explicit call of the destructor
f(bar); // still valid as far as the compiler is concerned, but
//clearly not a good idea
|
I am a little confused. I gather from the rest of the thread that
the following is ok because the reference in f is const? Or am I
misunderstanding?
struct A
{
A(int y) (y){}
int x;
};
void f(const A& aRef){}
int main()
{
f(A(7));
return 0;
}
Assuming that the above is OK, how does the const-ness of aRef change
your assertion that the A(7) temporary would get destroyed before f
actually runs?
Thanx for your patience. It seems like the more I read this group, the
more I realize how much I dont understand about my longtime friend.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Adrian Sandor Guest
|
Posted: Wed Apr 21, 2004 2:05 pm Post subject: Re: const objects |
|
|
Teh wrote:
| Quote: | Anyway Adrian's solution is a bit redundant, it requires the ability
to be able to change the class while the same effect can be had for
any type.
|
Well, maybe it is, but...
| Quote: | For example:
[...]
foo(const_cast<X&>(cref(X())));
|
....is it legal to use const_cast on a const reference and then modify
the object? Of course most compilers have no problems with it, but I'm
asking from the standard's point of view.
And I wonder if your solution is also redundant; e.g. my compiler even
accepts foo((X&)X()); albeit with a warning (and yes, I know that
C-style casts are evil).
Anyway, you can also write it like this, at least in gcc 3.2:
struct X { };
template <typename T>
T& ref(const T& t) { return const_cast<T&>(t); }
void foo(X& x) { }
void foo(int& i) { i = 42; }
int main()
{
foo(ref(X()));
foo(ref( );
}
| Quote: | I suppose this could be useful when you have a function that takes a
reference as an "out param" which you don't care about and you don't
want to declare a dummy named variable.
|
exactly!
regards,
Adrian
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| 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
|
|