I simplified my code down to the root of the trouble:
//==============================================================================
// PRE-DEFINITIONS
#define GIVE_ME_ODD_BEHAVIOUR true
//==============================================================================
// INCLUDES
#include <iostream>
//==============================================================================
// TYPES
//------------------------------------------------------------------------------
template<typename T> struct X {
T data;
X() : data(0)
{ std::cout << "X construction @ " << this << std::endl; }
template<typename TT>
X(const X<TT> & other) : data(other.data)
{ std::cout << "X construction @ " << this << " from " << &other << std::endl; }
~X()
{ std::cout << "X destruction @ " << this << std::endl; }
template<typename TT>
void Copy(const X<TT> & other)
{ std::cout << "X copy @ " << this << " from " << &other << std::endl; }
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<typename T>
X<double> XConversion(const X<T> & other)
{
#if GIVE_ME_ODD_BEHAVIOUR
return X<double>(other);
#else
X<double> d;
d.Copy(other);
return d;
#endif
}
//==============================================================================
// MAIN
int main()
{
X<double> d;
X<int> i;
std::cout << std::endl;
d = XConversion(i);
std::cout << std::endl;
d = XConversion(d); // !!!
std::cout << std::endl;
return 0;
}
which, with
GIVE_ME_ODD_BEHAVIOUR true
gives the output:
X construction @ 0x23aa70
X construction @ 0x23aa60
X construction @ 0x23aa80 from 0x23aa60
X destruction @ 0x23aa80
X destruction @ 0x23aa90 // never created !!!
X destruction @ 0x23aa60
X destruction @ 0x23aa70
It seems similar to THIS problem but i do have the ctor defined. I see the copy elision optimisation point here but:
- why the copiler destructs the object that it optimised out and thus never created?
- how can I ensure that it does not happen ?
Additional info:
I tried gcc 4.8.1 and C++ Builder XE3, optimisation off, debug compilation, both with the same result.
I tried to remove the template-ness like
struct X {
double data
...
X(const X &)
...
};
but with the same result.
One way to solve this would be, e.g., to make the cctor private and to public the Copy method only. But this would prevent me (anybody) from even returning the object from a function...
Background:
I have a set of template classes that are mutually friends and convertible. The classes share the same data but manipulate them in different ways via partial specialisation. The instances may either do soft or raw copy of the data as needed. If they do the soft copy, ref counter is increased. With the extra deletion of the instance that was actually never created, the ref counter is decreased without its prior incrementation.