In profiling my program I realized that 10% of the code is spent in a stupid std::complex<double>()
constructor, using new std::complex<double>[size_of_array]
.
I have searched through the web and the default constructor for std::complex
seems to take as real and imaginary parts the values double(). Since C++ does not initialize double numbers, I wonder why g++ bothers to initialize std::complex
with zeros, and whether I could work around this through the whole program in some way (*)
(*) right now I have to special case the functions that create arrays of complex numbers to allocate uninitialized arrays of doubles and recast them as complex.
Edit: as pointed below, it was an oversight on my side. The default constructor has empty constructors for the real and imaginary part (http://en.cppreference.com/w/cpp/numeric/complex/complex)
complex( const T& re = T(), const T& im = T() );
but the specification then introduces special cases for double
complex(double re = 0.0, double im = 0.0);
It is this special case that introduces all the overhead, as it bypasses the actual default constructor of 'double' which does nothing (same as for int, long, float, etc).
I wonder why g++ bothers to initialize std::complex with zeros
Because the standard says it must do so, the default constructor is declared as:
constexpr complex(double re = 0.0, double im = 0.0);
so it sets both the members to zero.
It is normal for the standard library to safely initialize types, rather than leaving them uninitialized as you get with built-in types such as double
and int*
, for instance std::vector<double>
zero-initializes its elements too if you resize it so that new elements get added. You can control this for vector
by not adding elements to the vector
until you know what values you want them to have.
One possible workaround for complex
is to use a type that doesn't do the initialization:
struct D
{
D() noexcept { }; // does not initialize val!
D(double d) noexcept : val(d) { }
operator double() const noexcept { return val; }
D& operator=(double d) noexcept { val = d; return *this; }
double val;
};
Now if you use std::complex<D>
the default constructor does nothing. Add explicit
to the converting constructor and/or the conversion operator to suit your taste.