# Why does std::complex<> initialize its value to 0 upon default construction?

Doing so strikes me as a waste of time. Consider

std::complex<double> *a = new std::complex<double>[1<<28];


This could be near-instantaneous and only grab pages once they're used, except it isn't.

It appears I'm not the only one bothered by this:

http://listengine.tuxfamily.org/lists.tuxfamily.org/eigen/2011/01/msg00124.html

GCC's libstdc++ (4.6.3) even gloats with this fact:

  ///  Default constructor.  First parameter is x, second parameter is y.
///  Unspecified parameters default to 0.
_GLIBCXX_CONSTEXPR complex(const _Tp& __r = _Tp(), const _Tp& __i = _Tp())
: _M_real(__r), _M_imag(__i) { }


Worse, since the C++ standard doesn't specify a default constructor, this behavior may even be required. (Is this true?)

• Why not use a vector and reserve? std::vector<std::complex<double> > a; followed by a.reserve(1<<28); – James Custer Apr 21 '12 at 0:08
• Also, the standard does specify a default constructor. It is the one you quoted. It would be illegal to declare complex() along with a constructor that takes all default parameters. – James Custer Apr 21 '12 at 0:16
• @James: You still can't e.g. parallel initialize the memory. – Ben Voigt Apr 29 '12 at 21:12

I'd say initialization to zero follows the principle of least surprise. Having uninitialized values around is a prescription for errors, and surely initialization is a far cheaper process than almost anything else you're going to do later on with these complex numbers. For example, allocating and initializing to zero 1<<28 complex values can be done with one malloc and one memset.

• This is a disaster in a threaded environment: the thread issuing new faults the entire array, causing all the memory to reside on one memory bus. If you subsequently access it simultaneously from threads, the aggregate memory bandwidth will be the bandwidth of that one bus. It's generally preferable to allocate the array with a prescribed memory policy (e.g. via libnuma) or to allocate the array without faulting it and subsequently fault the array with thread ownership distributed as it will be used so that it gets distributed across all memory buses. Yet another reason to avoid C++ new. – Jed Brown Apr 22 '12 at 20:09
• Or at least to allocate the memory from the thread that uses it. – Wolfgang Bangerth Apr 25 '12 at 6:06
• Of course, if you're concerned about these sorts of things, you may as well do this: <code> complex_array = reinterpret_cast<std::complex<double>*> (new char[sizeof(std::complex<double>) * array_size]); </code> That also doesn't initialize the memory. – Wolfgang Bangerth Apr 25 '12 at 6:07
• @Wolfgang: Formally, that also invokes undefined behavior (if you dereference the pointer afterwards), because it breaks strict-aliasing. Section 3.8 of the Standard says "The lifetime of an object of type T begins when: — storage with the proper alignment and size for type T is obtained, and — if the object has non-trivial initialization, its initialization is complete." Your code only fulfills the first step. Without the second step, this memory cannot be treated as instances of std::complex<double>. – Ben Voigt Apr 29 '12 at 21:10
• @BenVoigt: Yes. Maybe. It's true that you end up with an object for which you haven't run the constructor and, strictly speaking, you can not make any assumptions about whether the resulting object is in any internally consistent state that allows it to be used in any predictable way. My assumption -- which I confidently claim to be true for any implementation in current compilers -- is that the constructor actually only sets the elements to zero and so objects are readily usable in practice even though the constructor has not run. No guarantee, but likely true in practice. – Wolfgang Bangerth May 3 '12 at 1:38