It's expected behaviour. There are two concepts, "default initialization" and "value initialization". If you don't mention any initializer, the object is "default initialized", while if you do mention it, even as () for default constructor, the object is "value initialized". When constructor is defined, both cases call default constructor. But for built-in types, "value initialization" zeroes the memory whereas "default initialization" does not.
So when you initialize:
Type x;
it will call default constructor if one is provided, but primitive types will be uninitialized. However when you mention an initializer, e.g.
Type x = {}; // only works for struct/class without constructor
Type x = Type();
Type x{}; // C++11 only
a primitive type (or primitive members of a structure) will be VALUE-initialized.
Similarly for:
struct X { int x; X(); };
if you define the constructor
X::X() {}
the x member will be uninitialized, but if you define the constructor
X::X() : x() {}
it will be VALUE-initialized. That applies to new
as well, so
new int;
should give you uninitialized memory, but
new int();
should give you memory initialized to zero.
Unfortunately the syntax:
Type x();
is not allowed due to grammar ambiguity and
Type x = Type();
is obliged to call default constructor followed by copy-constructor if they are both specified and non-inlineable.
C++11 introduces new syntax,
Type x{};
which is usable for both cases. If you are still stuck with older standard, that's why there is Boost.ValueInitialized, so you can properly initialize instance of template argument.
More detailed discussion can be found e.g. in Boost.ValueInitialized documentation.