C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

unanswered question about clause 8.5.3/5
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Bronek Kozicki
Guest





PostPosted: Sun Oct 24, 2004 4:02 am    Post subject: unanswered question about clause 8.5.3/5 Reply with quote



This question has been asked on comp.std.c++ week ago, no answer yet.

Here's relevant part of the C++ standard, clause 8.5.3/5:

---- citation begin
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
in one of the following ways (the choice is implementation-defined):
[...]
- A temporary of type "cv1 T2" [sic] is created, and a constructor is
called to copy the entire rvalue object into the temporary. The
reference is bound to the temporary or to a sub-object within the temporary.

The constructor that would be used to make the copy shall be callable
whether or not the copy is actually done.
---- citation end

Effectively rvalue of non-copyable class cannot be bound to const
reference. Thus following code is ill-formed:

class C
{
C(const C&);
public:
C(){}
};

void g(const C&) {}

int main()
{
g(C());
}

..... as well as following one:

class D
{
D(const D&);
friend D f();
public:
D(){}
};

D f() {return D();}

int main()
{
const D& d = f();
}


Some compilers seem to not implement this clause, ie. will compile at
least one of above code samples without error. These compilers are GCC
3.3.1 (regardless of compilation options), MSVC (all versions, with
"language extensions" enabled), Comeau (in non-strict mode), and
possibly more.

What's purpose of this clause in the C++ standard? Under what scenarios
it's useful enough to justify cost?


B.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Rob Williscroft
Guest





PostPosted: Sun Oct 24, 2004 2:42 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote



Bronek Kozicki wrote in
news:872cd$417a14ef$3e79757c$5254 (AT) nf1 (DOT) news-service-com in
comp.lang.c++.moderated:

Quote:
This question has been asked on comp.std.c++ week ago, no answer yet.

Here's relevant part of the C++ standard, clause 8.5.3/5:

---- citation begin
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
in one of the following ways (the choice is implementation-defined):
[...]
- A temporary of type "cv1 T2" [sic] is created, and a constructor is
called to copy the entire rvalue object into the temporary. The
reference is bound to the temporary or to a sub-object within the
temporary.

The constructor that would be used to make the copy shall be callable
whether or not the copy is actually done.
---- citation end

Effectively rvalue of non-copyable class cannot be bound to const
reference.

The thing about rvalue's is they aren't like other object's,

int f() { return 0; }

f() return's an rvalue and on most platform's this rvalue will
be in a register, so to bind this to a int const & a copy *must*
be made.

This could apply to any type with a purely compiler generated
copy constructor, say both of:

struct A { int a, b; };
struct B : A { int c; };

Or, for sufficiently smart compilers, any type with a purely
compiler generated or inline (or templated) copy constructors.

Rob.
--
http://www.victim-prime.dsl.pipex.com/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Andrew Koenig
Guest





PostPosted: Mon Oct 25, 2004 4:36 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote



"Bronek Kozicki" <brok (AT) rubikon (DOT) pl> wrote


Quote:
What's purpose of this clause in the C++ standard? Under what scenarios
it's useful enough to justify cost?

The purpose is to reduce the chance that code that compiles on one compiler
will fail to compile on another. Such situations make testing difficult,
because if your only compiler accepts a program, there is no easy way of
determining that another compiler will reject it.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Bronek Kozicki
Guest





PostPosted: Mon Oct 25, 2004 7:54 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

Rob Williscroft wrote:
Quote:
int f() { return 0; }

f() return's an rvalue and on most platform's this rvalue will
be in a register, so to bind this to a int const & a copy *must*
be made.

I guess you are talking about copy of return value. Do we need this copy
to be made *again* when binding return value to const reference? I do
not see any reason for that. And I do not want to enter compiler
optimization ground, as it is allowed to do anything under "as if" rule.

Quote:
This could apply to any type with a purely compiler generated
copy constructor, say both of:

copy constructor implicitly generated by compiler is always public -
again, I do not see any problem here. However, I still see problem that
I do not understand rationale behind clause cited in my post.


B.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
johnchx
Guest





PostPosted: Tue Oct 26, 2004 1:26 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

Rob Williscroft <rtw (AT) freenet (DOT) co.uk> wrote

Quote:
The thing about rvalue's is they aren't like other object's,

int f() { return 0; }

f() return's an rvalue and on most platform's this rvalue will
be in a register, so to bind this to a int const & a copy *must*
be made.

This could apply to any type with a purely compiler generated
copy constructor, say both of:

struct A { int a, b; };
struct B : A { int c; };

Or, for sufficiently smart compilers, any type with a purely
compiler generated or inline (or templated) copy constructors.


A rationale along these lines occured to me too, but I don't think it
actually holds water. Two problems:

(1) An rvalue of class type always denotes an object (3.10/2) and an
object is a region of storage (1.8/1). Only an rvalue of built-in
type is allowed to denote a value which is not an object (i.e. which
exists only in a register). A compiler might be able to return a
value of class type in a register as an optimization under the as-if
rule, but only if it can do so without affecting the semantics of the
program.

(2) It is possible to call a non-static member function of a class via
an rvalue, without copying the object denoted by the rvalue. That
means that it is always possible to obtain the object's address
(supplied as the this pointer) without invoking the copy constructor
(or requiring that it be accessible).

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Rob Williscroft
Guest





PostPosted: Tue Oct 26, 2004 1:28 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

Bronek Kozicki wrote in news:ec5c6$417bf369$3e79757c$9291 (AT) nf1 (DOT) news-service-
com in comp.lang.c++.moderated:

Quote:
Rob Williscroft wrote:
int f() { return 0; }

f() return's an rvalue and on most platform's this rvalue will
be in a register, so to bind this to a int const & a copy *must*
be made.

I guess you are talking about copy of return value. Do we need this
copy to be made *again*

There is no *again* the rvalue is normally "copied" into a register by
the called function and is used by the caller still in the register.

i.e. no copy is made by the caller except when it needs to do an rvalue
to lvalue conversion.

Quote:
when binding return value to const reference?
I do not see any reason for that. And I do not want to enter compiler
optimization ground, as it is allowed to do anything under "as if"
rule.

Yes, but they don't as they may not have enough information to
work out all the what-if's. If language rules can reduce the
number of what-if's then more compilers will produce high quality
optimized code.

Example TU:

struct X
{
int a;
X( X const & ); /* defined in *another* TU */
};

X x = X();

The as-if rule isn't enough to optimize away the copy constructor
in the above, because the compiler has no idea what the copy
constructor does.

However the language rules do allow the compiler to remove the
call to the copy constructor and initialize x directly.

Quote:

This could apply to any type with a purely compiler generated
copy constructor, say both of:

copy constructor implicitly generated by compiler is always public -

Didn't say it wasn't.

But public access dosen't mean that the compiler has access to all
the source for the copy constructor (hence my use of the term pure
above).

Quote:
again, I do not see any problem here. However, I still see problem that
I do not understand rationale behind clause cited in my post.


Rob.
--
http://www.victim-prime.dsl.pipex.com/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
johnchx
Guest





PostPosted: Tue Oct 26, 2004 10:45 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

"Andrew Koenig" <ark (AT) acm (DOT) org> wrote
Quote:
"Bronek Kozicki" <brok (AT) rubikon (DOT) pl> wrote i

What's purpose of this clause in the C++ standard? Under what scenarios
it's useful enough to justify cost?

The purpose is to reduce the chance that code that compiles on one compiler
will fail to compile on another. Such situations make testing difficult,
because if your only compiler accepts a program, there is no easy way of
determining that another compiler will reject it.

Well sure, I suppose that's the purpose of *all* clauses in the
standard. :-)

But isn't the real question *why* the copy ctor needs to be accessible
in order to bind a reference to an rvalue of class type? I.e. is
there some architecture or implementation approach that would make it
difficult or impossible to bind a reference to an rvalue of class type
without copying?

I can't think of such a scenario that also allows us to call a
non-static member function on an rvalue of class type without copying.
But maybe I'm just overlooking something...stranger things have
happened.

[ 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





PostPosted: Tue Oct 26, 2004 11:30 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

"Andrew Koenig" <ark (AT) acm (DOT) org> wrote

Quote:
"Bronek Kozicki" <brok (AT) rubikon (DOT) pl> wrote in message
news:872cd$417a14ef$3e79757c$5254 (AT) nf1 (DOT) news-service-com...

What's purpose of this clause in the C++ standard? Under what
scenarios it's useful enough to justify cost?

The purpose is to reduce the chance that code that compiles on one
compiler will fail to compile on another. Such situations make testing
difficult, because if your only compiler accepts a program, there is
no easy way of determining that another compiler will reject it.

I think that the real question is: given a temporary of type T, and a
reference T const&, why does the standard allow making a copy?

There is a small category of classes which are designed to be used
almost exclusively as temporaries -- my GB_Format (and presumably also
boost::format) would be an example. The way I've implemented GB_Format,
there is internal state which means that the semantics of copying are at
best dubious. A deep copy would be very expensive, and a shallow copy
would cause problems with the state. Historically, I simply forbade
copying. With standard conformant compilers, however, I can't because
the standard requires an accessible copy constructor. So I'm forced to
define some arbitrary copy semantics which aren't really useful, or even
usable.

--
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

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Rob Williscroft
Guest





PostPosted: Wed Oct 27, 2004 12:02 am    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

johnchx wrote in news:4fb4137d.0410250605.289bac30 (AT) posting (DOT) google.com in
comp.lang.c++.moderated:

Quote:
Rob Williscroft <rtw (AT) freenet (DOT) co.uk> wrote

The thing about rvalue's is they aren't like other object's,

int f() { return 0; }

f() return's an rvalue and on most platform's this rvalue will
be in a register, so to bind this to a int const & a copy *must*
be made.

This could apply to any type with a purely compiler generated
copy constructor, say both of:

struct A { int a, b; };
struct B : A { int c; };

Or, for sufficiently smart compilers, any type with a purely
compiler generated or inline (or templated) copy constructors.


A rationale along these lines occured to me too, but I don't think it
actually holds water. Two problems:

(1) An rvalue of class type always denotes an object (3.10/2) and an
object is a region of storage (1.8/1).

Only an rvalue of built-in
type is allowed to denote a value which is not an object (i.e. which
exists only in a register).

I'm not finding any justification for the above is it a quote or
a conclusion ?

Quote:
A compiler might be able to return a
value of class type in a register as an optimization under the as-if
rule, but only if it can do so without affecting the semantics of the
program.

(2) It is possible to call a non-static member function of a class via
an rvalue, without copying the object denoted by the rvalue.

Is it /possible/ to do so (i.e. without the copy) or is it *required* to
do so, and do you have a quote/citation ?

Quote:
That
means that it is always possible to obtain the object's address
(supplied as the this pointer) without invoking the copy constructor
(or requiring that it be accessible).

Even so, when a class type has no member function's or all its member
function's are defined as inline this is not going to be a problem.

Further if a class defenition is sutible for puting in a register,
say:

struct X { int i; int f() };

Why cannot the compiler create rvalue version's of all members:

int f()
{
return i;
}

i.e:

extern "C" int __X_int_f_void_lvalue( /*register*/ X *that )
{
return that->i;
}

extern "C" int __X_int_f_void_rvalue( /*register*/ int member_i )
{
return member_i;
}

The linker can eliminate either (or both) if unused and the
compiler would return the first for &X::f.

Rob.
--
http://www.victim-prime.dsl.pipex.com/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Peter Dimov
Guest





PostPosted: Wed Oct 27, 2004 12:03 am    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

Bronek Kozicki <brok (AT) rubikon (DOT) pl> wrote

Quote:
This question has been asked on comp.std.c++ week ago, no answer yet.

Here's relevant part of the C++ standard, clause 8.5.3/5:

---- citation begin
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
in one of the following ways (the choice is implementation-defined):
[...]
- A temporary of type "cv1 T2" [sic] is created, and a constructor is
called to copy the entire rvalue object into the temporary. The
reference is bound to the temporary or to a sub-object within the temporary.

The constructor that would be used to make the copy shall be callable
whether or not the copy is actually done.
---- citation end

Effectively rvalue of non-copyable class cannot be bound to const
reference. [...]

What's purpose of this clause in the C++ standard?

I can construct a hypothetical example of an architecture that might
need to make a copy when binding a class rvalue to a const reference.

Imagine a CPU where the two registers R0 and R1 have addresses 0x10
and 0x14, and consider the following example:

class X
{
private:

int a;
int * p; // inv: p == &a

public:

X(): a( 0 ), p ( &a ) {}
X( X const & rhs ): a( rhs.a ), p ( &a ) {}
};

void f( X const & x );

int main()
{
f( X() );
}

X() creates an rvalue that lives in R0=0 and R1=0x10. A reference to
this object needs to be passed to f. However, passing 0x10, the
address of R0, would be bad, because f would likely need to use the
registers itself. Therefore, a copy of the rvalue needs to be made. In
order to preserve the invariant of X, this copy needs to be done via
the copy constructor.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
johnchx
Guest





PostPosted: Thu Oct 28, 2004 1:52 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

[email]pdimov (AT) gmail (DOT) com[/email] (Peter Dimov) wrote
Quote:
I can construct a hypothetical example of an architecture that might
need to make a copy when binding a class rvalue to a const reference.

Imagine a CPU where the two registers R0 and R1 have addresses 0x10
and 0x14, and consider the following example:

class X
{
private:

int a;
int * p; // inv: p == &a

public:

X(): a( 0 ), p ( &a ) {}
X( X const & rhs ): a( rhs.a ), p ( &a ) {}
};

void f( X const & x );

int main()
{
f( X() );
}

X() creates an rvalue that lives in R0=0 and R1=0x10. A reference to
this object needs to be passed to f. However, passing 0x10, the
address of R0, would be bad, because f would likely need to use the
registers itself. Therefore, a copy of the rvalue needs to be made. In
order to preserve the invariant of X, this copy needs to be done via
the copy constructor.

OK, but....

(a) How do you call a member function of a temporary X without
copying?

(b) Since f() could clobber R0 and/or R1, thus ending the lifetime of
the temporary (by re-using its "storage") the implementation would
have to ensure that ~X() (if it were non-trivial) would be executed
before entry to the function. That would violate the order of
destruction of temporaries created when binding an rvalue to a
reference.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Bronek Kozicki
Guest





PostPosted: Thu Oct 28, 2004 1:59 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

Peter Dimov wrote:
Quote:
class X
{
private:

int a;
int * p; // inv: p == &a

public:

X(): a( 0 ), p ( &a ) {}
[...]
X() creates an rvalue that lives in R0=0 and R1=0x10. A reference to
[...]


I would argue that any value of X type (rvalue or lvalue) may *not* live
in registers, because one of its members is initialized with address of
the other one. Thus, in order for X::p to be initialized with valid
memory address, object needs to be placed in memory - where it will stay
for the duration of function "void f(X const &)" call). Thus there's
still no need to make a copy, unless you need aggresive optimization -
and as we know, any kind of optimization is allowed by the C++ standard
under "as if" rule.


B.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Bronek Kozicki
Guest





PostPosted: Thu Oct 28, 2004 2:01 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

Andrew Koenig wrote:
Quote:
The purpose is to reduce the chance that code that compiles on one
compiler will fail to compile on another. Such situations make
testing difficult, because if your only compiler accepts a program,
there is no easy way of determining that another compiler will reject
it.

Thank you for your answer. I'm really pleased to see authorities like
you interested in this issue. But still I believe that in this case
solution (ie. clause I cited) of the problem (ie. standarized behaviour)
that you described is just opposite to intended. That's because code
that intuitively should be correct - is actually ill-formed due to said
clause (see code snippets in my first post, also James Kanze post in
this thread describing more general problem). Thus currently the
situation is that some compilers choose to compile such (ill-formed)
code, fulfilling programmers expectations, while some compilers reject
such code as ill-formed. Even some best conforming compilers (like
Comeau) provide compilation options that allow compilation of such
(ill-formed) code, at least on specific platform. Also, many compilers
are not consistent in what they choose to allow and what they choose to
reject (ie. of two snippets presented in my first post only one might be
compiled, but the other rejected). Thus result of said clause is just
opposite to indented (ie. standarized behaviour) - code that can be
compiled on some compiler is rejected by another. Clearly bad case of
standarization, and clear indication that there is existing practice
that is just opposite to the C++ standard.

I was directed by Michiel Salters (on comp.std.c++ ) to CWG issues 391,
I also checked 291 and 450. So, it appears that C++ Committee is aware
of the issue and is working on solution. That's great; do you know if
there is any chance to change C++ standard to required direct binding of
rvalue, thus eliminating need for publicly accessible copy constructor?
If so, note in "Notes from the March 2004 meeting" probably contains
error (as Michiel Salters noted on comp.std.c++ ), where it should be
reported?

Thank you and kind regards


Bronek Kozicki




[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Peter Dimov
Guest





PostPosted: Fri Oct 29, 2004 2:34 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

[email]johnchx2 (AT) yahoo (DOT) com[/email] (johnchx) wrote in message
news:<4fb4137d.0410270611.5ff48e35 (AT) posting (DOT) google.com>...
Quote:
pdimov (AT) gmail (DOT) com (Peter Dimov) wrote
[...]
X() creates an rvalue that lives in R0=0 and R1=0x10. A reference to
this object needs to be passed to f. However, passing 0x10, the
address of R0, would be bad, because f would likely need to use the
registers itself. Therefore, a copy of the rvalue needs to be made. In
order to preserve the invariant of X, this copy needs to be done via
the copy constructor.

OK, but....

(a) How do you call a member function of a temporary X without
copying?

Yes, I realized this too, right after posting. X().f() and f( X() )
are no different.

Quote:
(b) Since f() could clobber R0 and/or R1, thus ending the lifetime of
the temporary (by re-using its "storage") the implementation would
have to ensure that ~X() (if it were non-trivial) would be executed
before entry to the function. That would violate the order of
destruction of temporaries created when binding an rvalue to a
reference.

It seems that the caller can just save and restore R0 and R1... but I
think that you're right for this case, too. X::X() can register the
object in a registry which f() can then enumerate.

Well, I'm out of ideas. :-)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
David Abrahams
Guest





PostPosted: Fri Oct 29, 2004 2:41 pm    Post subject: Re: unanswered question about clause 8.5.3/5 Reply with quote

Bronek Kozicki <brok (AT) rubikon (DOT) pl> wrote

Quote:
This question has been asked on comp.std.c++ week ago, no answer yet.

Here's relevant part of the C++ standard, clause 8.5.3/5:

---- citation begin
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
in one of the following ways (the choice is implementation-defined):
[...]
- A temporary of type "cv1 T2" [sic] is created, and a constructor is
called to copy the entire rvalue object into the temporary. The
reference is bound to the temporary or to a sub-object within the temporary.

The constructor that would be used to make the copy shall be callable
whether or not the copy is actually done.
---- citation end

Effectively rvalue of non-copyable class cannot be bound to const
reference. Thus following code is ill-formed:

<snip code>

Quote:
Some compilers seem to not implement this clause, ie. will compile at
least one of above code samples without error. These compilers are GCC
3.3.1 (regardless of compilation options), MSVC (all versions, with
"language extensions" enabled), Comeau (in non-strict mode), and
possibly more.

By one valid interpretation, it's Comeau in strict mode that's
non-conforming.

See http://tinyurl.com/5smro#the-interpretation-problem

Fortunately, the CWG resolved in Redmond that there is never any need
for a copy of the temporary, so the rule can be lifted.

HTH,

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.