Uninitialized std :: complex constructor when using 'new'

In profiling my program, I realized that 10% of the code is spent on the stupid constructor std::complex<double>() using new std::complex<double>[size_of_array] .

I searched over the Internet, and the default constructor for std::complex seems to take double () as the real and imaginary parts. Since C ++ does not initialize double numbers, I wonder why g ++ is trying to initialize std::complex zeros and can I get around this through the whole program somehow (*)

(*) right now I have a special case that creates arrays of complex numbers to highlight uninitialized arrays of twins and reconstructs them as complex ones.

Edit: as indicated below, it was supervision on my side. The default constructor has empty constructors for the real and imaginary parts ( 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); 

This special case introduces all the overhead because it bypasses the actual default constructor "double", which does nothing (the same as for int, long, float, etc.).

+7
c ++ c ++ 11 default-constructor
source share
3 answers

I wonder why g ++ is trying to initialize std :: complex with zeros

Since the standard says that it should do this, the default constructor is declared as:

 constexpr complex(double re = 0.0, double im = 0.0); 

therefore, it sets both terms to zero.

Usually the standard library safely initializes types, instead of leaving them uninitialized, since you get with built-in types like double and int* , for example std::vector<double> zero-initializes its elements if you resize it so to add new elements. You can control this for vector without adding elements to vector until you know what values ​​you want to have.

One possible workaround for complex is to use a type that does not initialize:

 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 transform constructor and / or transform operator to suit your taste.

+5
source share

Is there an easy way to do this. If you "reserve" memory with std :: vector it is much faster because it does not call the constructor for each element.

those. this is:

 std::vector< std::complex< double > > vec; vec.reserve( 256 ); for( int i = 0; i < 256; i++ ) { vec.push_back( std::complex< double >( 1, 1 ) ); } 

will be significantly faster than this:

 std::complex< double >* arr = new std::complex< double >[256]; for( int i = 0; i < 256; i++ ) { arr[i]( std::complex< double >( 1, 1 ) ); } delete[] arr; 

because the constructor is called only once in the first example.

This has the added benefit that you have RAII on your side, and 'vec' will be automatically released when it goes beyond.

+4
source share

Below is the code I'm developing.

Added later: As MM noted in the comments, the behavior is technically undefined. Now I see that if some messy weasel had to change the implementation of std :: complex, so that it could not be trivially built / destroyed, this would bring pruning. See also an example at http://en.cppreference.com/w/cpp/types/aligned_storage .

 #include <complex> #include <type_traits> typedef std::complex<double> complex; // Static array of complex that does not initialize // with zeros (or anything). template<unsigned N> struct carray { typedef std::aligned_storage<sizeof(complex), alignof(complex)>::type raw; raw val[N]; complex& operator[] (unsigned idx) { return reinterpret_cast<complex&> (val[idx]); } complex* begin() { return &operator[](0); } complex* end() { return &operator[](N); } }; 
0
source share

All Articles