🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

5 total messages Started by eddy Gorsuch Thu, 25 Jan 1996 16:12
Explicit constructor call vs Temporaries
#3146
Author: eddy Gorsuch
Date: Thu, 25 Jan 1996 16:12
34 lines
1643 bytes
Is an explicit call to an object constructor (an unamed object) const or
not? I have code like the following where I don't care about the parameter
to X::f(), so I just created an unamed T(). I thought I had tried to compile
this code and got errors about trying to pass a const object to a non const
reference parameter. Thinking that the unamed T() counts as a temporary (and
therefor const) object, I believed that the compiler was right. Now somebody
tells me that the following code is legal. Is it?

class T {
  T();
  ~T();
}

class X {
  X();
  ~X();
  f(T& t);
}

int main() {
  X x;
  x.f(T());  // Compiler complained on this line
}

eddy
-- 
ed.dy \'ed-e-\ n [ME (Sc dial.) ydy, prob. fr. ON itha; akin to OHG ith- 
   again], L et and 1a: a current of water or air running contrary to the main 
   current; esp)X : a small whirlpool 1b: a substance moving similarly  2: a 
   contrary or circular current  - eddy vb

[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Explicit constructor call vs Temporaries
#3189
Author: Tilo Koerbs
Date: Thu, 01 Feb 1996 17:54
39 lines
1506 bytes
 About the error message in this posted code:

> class T {
>   T();
>   ~T();
> }
> 
> class X {
>   X();
>   ~X();
>   f(T& t);
> }
> 
> int main() {
>   X x;
>   x.f(T());  // Compiler complained on this line
> }

The 'temporary' (it is an UNNAMED) T()-object is NOT const!
Consider:
	class T {
	public:
		T();
		~T();
		void nonConstFct() {}
	};

	int main() {
		T().nonConstFct();  // Allowed!!!
	}

And so the compiler should have no problem with this code!
I compiled it without any problem!

Bye.
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Explicit constructor call vs Temporaries
#3204
Author: David Sachs
Date: Thu, 01 Feb 1996 22:54
33 lines
1712 bytes
eddy@siemensrolm.com (eddy Gorsuch) writes:

>Is an explicit call to an object constructor (an unamed object) const or
>not? I have code like the following where I don't care about the parameter
>to X::f(), so I just created an unamed T(). I thought I had tried to compile
>this code and got errors about trying to pass a const object to a non const
>reference parameter. Thinking that the unamed T() counts as a temporary (and
>therefor const) object, I believed that the compiler was right. Now somebody
>tells me that the following code is legal. Is it?

>class T {
>  T();
>  ~T();
>}

>class X {
>  X();
>  ~X();
>  f(T& t);
>}

>int main() {
>  X x;
>  x.f(T());  // Compiler complained on this line
>}

Doesn't the statement violate the rule that a temporary may not be
used for a non-const reference parameter of a function?

[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy is
  summarized in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
]
Re: Explicit constructor call vs Temporaries
#3199
Author: Matt Austern
Date: Thu, 01 Feb 1996 22:54
72 lines
3095 bytes
In article <4eq5p2$fpu@fsuj01.rz.uni-jena.de> mkt@isun04.inf.uni-jena.de (Tilo Koerbs) writes:

>  About the error message in this posted code:
> 
> > class T {
> >   T();
> >   ~T();
> > }
> > 
> > class X {
> >   X();
> >   ~X();
> >   f(T& t);
> > }
> > 
> > int main() {
> >   X x;
> >   x.f(T());  // Compiler complained on this line
> > }
> 
> The 'temporary' (it is an UNNAMED) T()-object is NOT const!
> Consider:
> 	class T {
> 	public:
> 		T();
> 		~T();
> 		void nonConstFct() {}
> 	};
> 
> 	int main() {
> 		T().nonConstFct();  // Allowed!!!
> 	}
> 
> And so the compiler should have no problem with this code!
> I compiled it without any problem!

It's true that T().nonConstFct() is legal.  It's also true that 
x.f(T()) is illegal.  Those two cases are very different!

The issue isn't whether what T() returns is const, but whether it's an
lvalue.  This is a crucial point, since a non-const reference may not
be bound to an rvalue.  Unfortunately, you have to read section 8.5.3
[dcl.init.ref] a little bit carefully to see this; it's quite
unambiguous, though.  Paragraph 8 begins "--Otherwise [i.e. if a
reference is being initialized with an rvalue], the reference shall be
to a non-volatile const type (i.e., cv1 shall be const)."

(As usual, the complicated language in 8.5.3 simply formalizes what
you'd expect anyway.  Creating a reference to a temporary is a
problematic operation, so it's forbidden except in certain restricted
cases.)

And, indeed, the explicit invocation of a constructor yields an
rvalue.  The draft standard says this in several places, and implies
it in others.  One such place is section 3.10 [basic.lval], paragraph
5: "Constructor invocations and calls to functions that do not return
references are always rvalues."  See also the footnote to paragraph 2:
"Expressions such as invocations of constructors and of functions that
return a class type refer to objects, and the implementation can
invoke a member function upon such objects, but the expressions are
not lvalues."


-- 
Matt Austern
SGI: MTI Compilers Group
austern@isolde.mti.sgi.com

[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy is
  summarized in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
]
Re: Explicit constructor call vs Temporaries
#3206
Author: James Kanze US/ESC 60/3/141 #407...
Date: Fri, 02 Feb 1996 15:49
130 lines
4659 bytes
In article <4eq5p2$fpu@fsuj01.rz.uni-jena.de>
mkt@isun04.inf.uni-jena.de (Tilo Koerbs) writes:

|>  About the error message in this posted code:

|> > class T {
|> >   T();
|> >   ~T();
|> > }
|> > 
|> > class X {
|> >   X();
|> >   ~X();
|> >   f(T& t);
|> > }
|> > 
|> > int main() {
|> >   X x;
|> >   x.f(T());  // Compiler complained on this line
|> > }

|> The 'temporary' (it is an UNNAMED) T()-object is NOT const!
|> Consider:
|> 	class T {
|> 	public:
|> 		T();
|> 		~T();
|> 		void nonConstFct() {}
|> 	};

|> 	int main() {
|> 		T().nonConstFct();  // Allowed!!!
|> 	}

|> And so the compiler should have no problem with this code!
|> I compiled it without any problem!

Except that the rules forbid binding a temporary to a non-const
reference, independantly of whether the temporary is const or not.
(See section 8.5.3 in the draft standard: "If the initializer
expression is an lvalue ... Otherwise, the reference shall be to a
non-volatile const type."

Both g++ 2.7.2 and Sun CC 3.0.1 (the old cfront version) issue
warnings about this.  Curiously enough, Sun CC 4.0.1 doesn't, on this
platform (Sun CC 4.1), although I seem to remember warnings from this
compiler under Solaris.  The Sun warnings state "anachronism", and in
fact, this rule was added to the language (at least five or six years
ago), so some older compilers may not be aware of it.

The rule was introduced to avoid errors in cases like the following:

	void
	incr( int& i )
	{
	    i ++ ;
	}

	void
	user()
	{
	    unsigned        x( 5 ) ;
	    incr( x ) ;
	}

In the call to `incr', the compiler must convert x to an int; the
result of such a conversion is a temporary.  Before the rule was
adapted, the temporary was bound to the reference, and modified by the
function `incr'.  This is generally *NOT* what the author of user
wanted or expected (since `x' remains unchanged).  Note that this is
not a problem with const references, since there is presumably no
modification to get lost.

The solution I'm using (since yesterday, when I thought of it:-) is to
add a function to T:

	T&
	T::lvalue()
	{
	    return *this ;
	}

And in the main, above:

	int
	main()
	{
	    X               x ;
	    x.f( T().lvalue() ) ;
	    return 0 ;
	}

As you point out, the temporary isn't const, so I can call a non-const
function (like `lvalue') on it.  And a reference *is* an lvalue (by
definition), so it can bind to a non-const reference.

This solution has the advantage (IMHO) of requiring the user to say,
yes, I know that I'm going to modify a temporary, but that's what I
want.  It also retains const-safety; as the function `lvalue' is not
const, it cannot be called on a const object.

The major disadvantage is that it requires adding a function to T.
For classes where one expects this type of behavior (e.g.: auto_ptr),
one would probably add the function.  But the user who needs it
exceptionally for a class where it is not the normal case is stuck.
(I have a case where I need it from ostrstream!)  Of course, there is
always derivation:

	class MyStrStream : public ostrstream
	{
	public :
	    ostrstream&         lvalue() { return *this ; }
	} ;

I'm not sure, but I think that `static_cast< T& >( T() )' should also
work.  (This is OK for the occasional exceptional usage, but for cases
where I expect my user to normally use a temporary, I'll provide the
derived class.)

--
James Kanze         Tel.: (+33) 88 14 49 00        email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, études et réalisations en logiciel orienté objet --
                -- A la recherche d'une activité dans une region francophone


[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy is
  summarized in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
]
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads