Ng *_*ang 7 c++ polymorphism virtual undefined-behavior language-lawyer
在定义为基础对象的向量/数组中放置新的派生对象是否合法
#include <iostream>
#include <memory>
#include <vector>
struct A
{
virtual ~A()
{
std::cout << "~A()" << std::endl;
}
};
struct B : public A
{
virtual ~B()
{
std::cout << "~B()" << std::endl;
}
};
int main()
{
std::vector<A> a(1);
a[0].~A();
:: new(std::addressof(a[0])) B();
}
Run Code Online (Sandbox Code Playgroud)
这是合法的 C++ 吗?
这个问题与这里的问题有关。讨论的要点是我们能够在编译时确定向量/数组中对象的类型,因此我们不必进行任何动态分派。我们可以使用这些信息来优化 gcc 现在正在做的事情。
我在这里向 gcc 提出了一个问题,反对这种优化的论点是,我们可能会放置新的内容来更改存储在向量/数组中的类型,但我们不确定它是否合法,因此出现了这个 stackoverflow 问题。
有趣的是,对于数组,gcc 的行为与 clang 不同,并且 gcc 本身根据数组的长度有不同的行为。当 len >= 3 时,它执行虚拟 dtor,但当 len < 3 时,它执行合格的 dtor 调用。
https://godbolt.org/z/f33Gh5EGM
编辑:
问题纯粹是“这是合法的 C++ 吗”。问题中的任何其他信息都是为了说明我为什么要问这样的问题。
Mes*_*kon -1
注意:这个结论是基于语义的,::delete[]并且可能会或可能不会转移到自动存储阵列的破坏。
如果我们查看::delete[]then的文档,我们可以找到关于删除数组类型的声明
对于第二种(数组)形式,表达式必须是空指针值或先前由 new-expression 的数组形式获得的指针值,其分配函数不是非分配形式(即重载(10))。表达式指向的类型必须与数组对象的元素类型相似。如果表达式是其他任何内容,包括如果它是通过 new-expression 的非数组形式获得的指针,则行为未定义。
那么表达式的指向类型必须与数组的元素类型相似是什么意思呢?
如果我们看看如何similar定义,那么我们会发现这个语句
非正式地,如果忽略顶级简历资格,两种类型是相似的:
它们是相同的类型;或者
都是指针,且指向的类型相似;或者
都是指向同一个类的成员的指针,并且所指向的成员的类型相似;或者
它们都是相同大小的数组或都是未知边界的数组,并且数组元素类型相似。(C++20 之前)
它们都是相同大小的数组,或者至少其中一个是未知边界数组,并且数组元素类型相似。(自 C++20 起)
假设数组的元素类型是 ,A指向的类型是 ,我们可以通过that和are notB的非正式定义看到。因此,根据这种行为是未定义的。similarABsimilar::delete[]