J
JurgenvonOerthel
Consider the classes Base, Derived1 and Derived2. Both Derived1 and
Derived2 derive publicly from Base.
Given a 'const Base &input' I want to initialize a 'const Derived1
&output'.
If the dynamic type of 'input' is Derived1, then 'output' should
become a reference to 'input'.
Otherwise 'output' should become a reference to the (temporary) result
of the member function 'input.to_der1()' which returns a Derived1
object by value.
For performance reasons the copy constructor of Derived1 must not be
called.
In trying to achieve this I used the following code:
Example #1:
const Derived2 *der2_ptr = dynamic_cast<const Derived2*>(&input);
const Derived1 &output =
(der2_ptr)?
der2_ptr->to_der1() :
static_cast<const Derived1 &>(input);
This works fine if 'der2_ptr != NULL', but when 'der2_ptr == NULL'
then Derived1's copy constructor is called (possibly because the
second and third argument of the conditional operator have to be
converted to the same type).
Alternatively I used the following code:
Example #2:
const Base &base =
(der2_ptr)?
der2_ptr->to_der1() :
input;
const Derived1 &output = static_cast<const Derived1&>(base);
This is even worse. It exposes a bug in g++ 3.4.x (the temporary
result of 'to_der1()' is destroyed before it has been used) and with g+
+ 4.x the copy constructor of Base (!) is called on the result of
'to_der1()' making the static_cast from 'base' to 'Derived1' invalid
(and still, a copy is made).
So why is this copy necessary? All the objects are there. It should be
possible to setup a reference to them without making a meaningless
copy.
G++ (incl. 4.x) even makes a copy in the following case:
Example #3:
Base my_base;
const Base &output =
(der2_ptr)?
der2_ptr->to_base() :
my_base;
The 'to_base' function returns a Base object by value.
I don't see why this copy is necessary while arguments 2 and 3 of
the ?: operator are both of type 'Base'.
I would say that at least in example #3 the situation is as described
by the C++ standard in 5.16:3 (first bullet). So either no conversions
or implicit conversions should occur. However, it looks like g++
treats the situation as in the second bullet, where a conversion
occurs by creating a temporary object.
Another possibility is that I am wrong and g++ is right because
paragraph 8.5.3:5 last bullet applies and the copy is 'necessary' to
initialize the reference (although it just looks like a waste to me).
My questions are:
- Why is the copy constructor called in the examples above? Is that
because of the standard (if so, what section) or is it because of g++?
- If the copies are necessary, is there another way to set up 'output'
without making copies?
Derived2 derive publicly from Base.
Given a 'const Base &input' I want to initialize a 'const Derived1
&output'.
If the dynamic type of 'input' is Derived1, then 'output' should
become a reference to 'input'.
Otherwise 'output' should become a reference to the (temporary) result
of the member function 'input.to_der1()' which returns a Derived1
object by value.
For performance reasons the copy constructor of Derived1 must not be
called.
In trying to achieve this I used the following code:
Example #1:
const Derived2 *der2_ptr = dynamic_cast<const Derived2*>(&input);
const Derived1 &output =
(der2_ptr)?
der2_ptr->to_der1() :
static_cast<const Derived1 &>(input);
This works fine if 'der2_ptr != NULL', but when 'der2_ptr == NULL'
then Derived1's copy constructor is called (possibly because the
second and third argument of the conditional operator have to be
converted to the same type).
Alternatively I used the following code:
Example #2:
const Base &base =
(der2_ptr)?
der2_ptr->to_der1() :
input;
const Derived1 &output = static_cast<const Derived1&>(base);
This is even worse. It exposes a bug in g++ 3.4.x (the temporary
result of 'to_der1()' is destroyed before it has been used) and with g+
+ 4.x the copy constructor of Base (!) is called on the result of
'to_der1()' making the static_cast from 'base' to 'Derived1' invalid
(and still, a copy is made).
So why is this copy necessary? All the objects are there. It should be
possible to setup a reference to them without making a meaningless
copy.
G++ (incl. 4.x) even makes a copy in the following case:
Example #3:
Base my_base;
const Base &output =
(der2_ptr)?
der2_ptr->to_base() :
my_base;
The 'to_base' function returns a Base object by value.
I don't see why this copy is necessary while arguments 2 and 3 of
the ?: operator are both of type 'Base'.
I would say that at least in example #3 the situation is as described
by the C++ standard in 5.16:3 (first bullet). So either no conversions
or implicit conversions should occur. However, it looks like g++
treats the situation as in the second bullet, where a conversion
occurs by creating a temporary object.
Another possibility is that I am wrong and g++ is right because
paragraph 8.5.3:5 last bullet applies and the copy is 'necessary' to
initialize the reference (although it just looks like a waste to me).
My questions are:
- Why is the copy constructor called in the examples above? Is that
because of the standard (if so, what section) or is it because of g++?
- If the copies are necessary, is there another way to set up 'output'
without making copies?