Topic: Binding to references [Was: Passing the result of an explicitly called constructor]
Author: jbarfurth@vossnet.de (Joerg Barfurth)
Date: 1999/12/14 Raw View
John Potter <jpotter@falcon.lhup.edu> wrote:
> On 11 Dec 99 16:20:22 GMT, Valentin Bonnard <Bonnard.V@wanadoo.fr>
> wrote:
>=20
> : Tom Payne wrote:
[Binding a D rvalue to a reference to const B; D being publically
derived from B]
> : > Does the entire D rvalue get copied, or does it
> : > get sliced down to a B rvalue?
> :=20
> : Nothing is copied. There might not exist any accessible=20
> : copy constructor anyway.
Ms. Bonnard failed to notice that 8.5.3/5 states that:
"The constructor that would be used to make the copy shall be callable
whether or not the copy is actually done."
That constructor needn't be a copy constructor though (see
std::auto_ptr).
> Interesting point. I have an implementation which seems to copy
> builtins but not UDTs. =20
The part of 8.5.3/5 allowing the choice applies only to class types
(where no conversion other than derived-to-base and possibly a
qualification conversion is involved).
In other cases (among them built-ins) a copy is required using
copy-initialization semantics. That copy will have the type of the
reference.
That rule disallows getting the address of a literal:
void foo(const int& r) { std::cout << &r; }
=20
foo(2); // wont yield the address of the literal 2 ;)
OTOH copies of temporaries might be elided as usual.
>In the example above, a reference of type
> B const is bound to an rvalue of type D. The implementation has
> a choice of binding it to the B part of that D or of creating a
> temporary of type D const and binding to the B part of that.
>=20
> If there is no accessible copy ctor, the program is well formed
> in the first case and ill formed in the second case.
It is ill-formed in either case.
> If f contains
> B& rp(const_cast<B&>(parm));
> the program is well behaved in the first case and has undefined
> behavior in the second case.
This is an interesting point. In a recent discussion someone proposed:
template <class T>=20
T& lvalue(T const& rvalue)
{ return const_cast<T&>(rvalue); }
// May be the original was a specialization of this
to allow something like:
lvalue( ifstream("Hello.txt") ) << "Hello World";
and similar uses for rvalues returned from functions.
It now seems that this proposal may lead to undefined behaviour (and the
example is ill-formed, as the copy c'tor for ifstream is missing).
> Is it really intended that an implementation decision can make
> these changes in the validity of a program?
The implementation decision does not make an ill-formed program
well-formed (your first concern). The other problem just shows how
dangerous const_cast is and invalidates its use in one more context.
OTOH I'd be surprised to see a case where the undefined behaviour caused
by the copy actually did behave differently. I dont expect
implementations to create temporaries of const type in read-only memory.
=20
> John
I also have a question of my own. Having:
struct B {=20
B();=20
B(B volatile const&);=20
virtual char const* name() const volatile { return "B"}
};
struct D {=20
D();=20
D(D volatile const&); };
virtual char const* name() const volatile { return "B"}
};
extern D foo();
extern D volatile bar();
void baz(B const& b) { std::cout << b.name() << std::endl; }
int main() {
baz( foo() );
baz( bar() );
}
It seems as though the output must be:
D
B
Am I right ? Is it legal at all ?
Also, if baz were changed to have signature=20
void baz(B volatile const&)=20
it seems that both calls to baz would be ill-formed.
How does this related to the signature of the copy constructors ? Can a
volatile rvalue be copied at all ?
-- J=F6rg Barfurth
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html ]