c++ - Visual Studio的C4345警告错了吗?

标签 c++ visual-c++ initialization c++11

以下代码触发C4345在标记线上:

#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

因此,根据他们的警告,第 10 行应该具有与写为

相同的行为
buf_type* pbuf = new (p) buf_type; // note the missing '()'

但是,输出不同。即,第一个版本将打印五个0,而第二个版本将打印五个5。因此,第一个版本确实是值初始化的(并且底层缓冲区是零初始化的),尽管 MSVC 说它不会。

这可以被认为是 MSVC 中的错误吗?还是我误解了警告/我的测试代码有问题?

最佳答案

TL;DR 版本:MSVC 的行为实际上是正确的,尽管警告不正确(应该是 value-initialized)。


对于new (p) buf_type;,MSVC执行默认初始化是正确的,因为标准(5.3.4 [expr.new])要求:

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 是一个类类型。对于类类型(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);

默认初始化仅对原始类型(及其原始数组)保留内存不变

另一方面,std::array 有一个默认的默认构造函数,因此成员本身应该被默认初始化。事实上,你观察到了这一点。


然后根据同一节,new (p) buf_type(); 版本导致直接初始化。

<罢工> std::array 是一个聚合,所以我认为这个规则(8.5.1 [dcl.init.aggr])然后适用:

<罢工>

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).

这意味着对所有元素进行值初始化。

不,这是规则(8.5 [dcl.init]):

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

聚合的值初始化意味着所有元素的值初始化,因为元素是原始的,这意味着零填充。

所以 MSVC 的行为实际上是正确的,虽然警告是不正确的(应该说 value-initialized)。

已经举报了,看

关于c++ - Visual Studio的C4345警告错了吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8697105/

相关文章:

c++ - 尝试创建大小未知的模板类的二维数组 (C++)

c# - 在第一次使用之前声明变量有什么缺点?

c++ - 如何在 OpenCV 中混合多个图像?

c++ - 我有一个表示整数的类,我想区分 lbs 和 kg 我该怎么做?

api - 如何学习 CATIA CAA V5 R18 c++ 中的流程

c++ - 在成员函数的默认参数中使用强类型枚举的成员

objective-c - NSString 属性和自定义初始化

c++ - CUDA 推力的 2D device_vector 错误

version-control - 在 Emacs Lisp 中获取 VC 根

arrays - 如何在 Pascal 中初始化数组?