The following code triggers C4345 on the marked line:
#include <array>
#include <iostream>
int main(){
static unsigned const buf_size = 5;
typedef std::array<char, buf_size> buf_type;
char buf[] = { 5, 5, 5, 5, 5 };
void* p = &buf[0];
buf_type* pbuf = new (p) buf_type(); // <=== #10
for(unsigned i=0; i < buf_size; ++i)
std::cout << (char)((*pbuf)[i] + 0x30) << ' ';
}
main.cpp(10): warning C4345: behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized
So, according to their warning, line 10 should have the same behaviour as if it was written as
buf_type* pbuf = new (p) buf_type; // note the missing '()'
However, the output differes. Namely, the first version will print five 0s, while the second version will print five 5s. As such, the first version is indeed value-initialized (and the underlying buffer zero-initialized), even though MSVC says it won’t.
Can this be considered a bug in MSVC? Or did I misinterpret the warning / is my test code faulty?
TL;DR version: MSVC’s behavior is actually correct, although the warning is incorrect (it should say value-initialized).
For
new (p) buf_type;, MSVC is correct to perform default initialization, because the standard (5.3.4[expr.new]) demands:std::arrayis a class type. For class types (8.5[dcl.init]):default-initialization leaves the memory unchanged only for primitive types (and raw arrays thereof)
On the other hand,
std::arrayhas a defaulted default constructor, so the members themselves ought to be default-initialized. And in fact you observed that.Then according to the same section, the
new (p) buf_type();version causes direct-initialization.std::arrayis an aggregate, so I think this rule (8.5.1[dcl.init.aggr]) then applies:And that means value-initialization for all elements.
Nope, here’s the rule (8.5
[dcl.init]):Value initialization of an aggregate means value initialization of all elements, since the elements are primitive, that means zero fill.
So MSVC’s behavior is actually correct, although the warning is incorrect (it should say value-initialized).
It’s already been reported, see