Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the C4345 warning of Visual Studio wrong?

Tags:

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?

like image 970
Xeo Avatar asked Jan 02 '12 03:01

Xeo


2 Answers

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:

A new-expression that creates an object of type T initializes that object as follows:

  • If the new-initializer is omitted, the object is default-initialized (8.5); if no initialization is performed, the object has indeterminate value.
  • Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct-initialization.

std::array is a class type. For class types (8.5 [dcl.init]):

To default-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type, the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

default-initialization leaves the memory unchanged only for primitive types (and raw arrays thereof)

On the other hand, std::array has 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::array is an aggregate, so I think this rule (8.5.1 [dcl.init.aggr]) then applies:

If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from an empty initializer list (8.5.4).

And that means value-initialization for all elements.

Nope, here's the rule (8.5 [dcl.init]):

An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.

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

  • VC9 erroneously generates C4345 when compiling value-initialized placement new expressions
like image 179
Ben Voigt Avatar answered Jan 17 '23 05:01

Ben Voigt


Here is how I read the MS article http://msdn.microsoft.com/en-us/library/wewb47ee%28v=vs.80%29.aspx

Under the old version of VS (your original syntax) - in this article, VS 2003 - a POD initialize would default initialize with 0s. Your code would support this.

Under the new version of VS - in this article, that would be VS 2005 - it was up to the programmer to initializes the POD explicitly as no default initialization was performed. In your case, as shown in your code, it correctly displays 5s.

Thus, as I read it, the old syntax initialized the POD to 0s even if your code had already explicitly initialized it. I do add a disclaimer that it is very late here and I am tired, so this may all be babbling.

like image 29
Gerald P. Wright Avatar answered Jan 17 '23 05:01

Gerald P. Wright