以下代码在标记的行上触发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) << ' ';
}
因此,根据他们的警告,第10行的行为应与写为
buf_type* pbuf = new (p) buf_type; // note the missing '()'
但是,输出不同。即,第一个版本将打印五个
0
,而第二个版本将打印五个5
。这样,即使MSVC表示不会,第一个版本的确确实是值初始化的(并且基础缓冲区为零初始化的)。可以认为这是MSVC中的错误吗?还是我误解了警告/我的测试代码是否错误?
最佳答案
TL; DR版本: MSVC的行为实际上是正确的,尽管警告是不正确的(应该说是值初始化的)。
对于new (p) buf_type;
,MSVC是执行默认初始化的正确方法,因为标准(5.3.4 [expr.new]
)要求:
std::array
是一个类类型。对于类类型(8.5 [dcl.init]
):
default-initialization只保留原始类型(及其原始数组)的内存不变
另一方面,std::array
具有默认的默认构造函数,因此成员本身应进行默认初始化。实际上,您观察到了这一点。
然后根据同一部分,new (p) buf_type();
版本将导致直接初始化。std::array
是一个聚合,因此我认为这条规则(8.5.1 [dcl.init.aggr]
)适用:
这意味着对所有元素进行值初始化。
不,这是规则(8.5 [dcl.init]
):
聚合的值初始化表示所有元素的值初始化,因为这些元素是原始元素,因此表示零填充。
因此,尽管警告是错误的,但MSVC的行为实际上是正确的(应该说是值初始化的)。
已经有报道了,看