C++ Placement new写入的字节数大于数组大小

C++ Placement new写入的字节数大于数组大小,c++,C++,在下面的程序中,我希望用placement new覆盖10个字节,然后为每个字节调用析构函数: #include <memory> struct MyChar { MyChar(char c = 'n') :c{c}{} ~MyChar(){ c = 'd'; } char c; }; int main() { { MyChar first[10]{0,1,2,3,4,5,6,7,8,9}; new (first)M

在下面的程序中,我希望用placement new覆盖10个字节,然后为每个字节调用析构函数:

#include <memory>

struct MyChar {
    MyChar(char c = 'n') :c{c}{}
    ~MyChar(){ c = 'd'; }
    char c;
};

int main()
{
    {
        MyChar first[10]{0,1,2,3,4,5,6,7,8,9};
        new (first)MyChar[10]{10,11,12,13,14,15,16,17,18,19};
    }
    return 0;
}
#包括
结构MyChar{
MyChar(char c='n'):c{c}{
~MyChar(){c='d';}
字符c;
};
int main()
{
{
MyChar first[10]{0,1,2,3,4,5,6,7,8,9};
新的(第一个)MyChar[10]{10,11,12,13,14,15,16,17,18,19};
}
返回0;
}
但编译器(*)警告将写入18:

警告C6386:写入“第一个”时缓冲区溢出:可写 大小为“10”字节,但可能会写入“18”字节

首先,按预期写入字节:

但编译器并不是在虚张声势。在placement new语句中,它会写入18个字节:

这会导致错误:

运行时检查失败#2-变量“first”周围的堆栈被删除 腐败

为什么不坚持10字节
sizeof(MyChar)==1
alignof(MyChar)==1



(*)微软Visual Studio社区2017预览版(2)。另外(但在编译过程中没有警告)我在Microsoft Visual Studio Community 2017(版本15.2(26430.15)发行版上收到了相同的内存覆盖和运行时错误。

放置新数组可能需要比
N*sizeof(Object)

(???as编译器必须能够使用
delete[]
???正确调用析构函数)

5.3.4[新增表述]:

new(2,f)T[5]
导致调用
operator new[](sizeof(T)*5+y,2,f)

这里,
x
y
是表示数组分配开销的非负未指定值;新表达式的结果将从
运算符new[]
返回的值中减去该值。此开销可应用于所有数组新表达式,包括引用库函数
运算符new[](std::size_t,void*)
和其他位置分配函数的表达式。开销的大小可能会因调用不同的new而有所不同-[结束示例]


如果不先调用现有对象的析构函数,则无法将新对象放置在现有对象上。您需要继续阅读。哪个编译器?我无法在gcc、clang和MSVC上复制警告。@bolov使用:Microsoft Visual Studio Community 2017预览版(2)UB的一个可能观察到的结果(请参阅dtor上的Francois)@FrançoisAndrieux:回答这个问题。@FrançoisAndrieux很奇怪,覆盖对象似乎定义得很好:[basic.life]4"... 对于具有非平凡析构函数的类类型的对象,在重用或释放该对象占用的存储之前,程序不需要显式调用析构函数;但是,如果没有显式调用析构函数,或者如果没有使用删除表达式(5.3.5)来释放存储,则不应隐式调用析构函数,并且依赖于析构函数产生的副作用的任何程序都具有未定义的行为。“我不确定这是否适用于新的安置。没有分配内存。那么解决方案就是为循环中的每个元素调用新的位置,对吗?@FrançoisAndrieux我相信[expr.new]间接地允许:如果实体是非数组对象,则新表达式返回指向所创建对象的指针。如果它是一个数组,新表达式将返回一个指向数组初始元素的指针。“@HolyBlackCat我看不出引号是如何应用的。你能详细说明一下吗?我不知道有。