使用 T[] 访问彼此相邻声明的两个 T 类型对象是否是未定义的行为?

nam*_*ame 5 c++ language-lawyer

我最近观看了 Miro Kenjp 关于“不符合标准的 C++:委员会向你隐藏的秘密”的 CppCon 演讲。

在 28:30 ( https://youtu.be/IAdLwUXRUvg?t=1710 ) 他说访问彼此相邻的双打是 UB,我不太明白为什么。有人可以解释为什么会这样吗?

如果是这种情况,那么它的 UB 肯定会以这种方式访问​​其他东西,例如:

int* twoInts = malloc(sizeof(int) * 2);
int secondInt = twoInts[1]; //Undefined behaviour?
Run Code Online (Sandbox Code Playgroud)

bol*_*lov 3

我想从演讲中引用一段话开始:

你不是针对CPU编程,你是针对抽象机编程

你说:

他表示,相邻的双打是 UB

但你的报价不完整。他详细说明了这个非常关键的事实:

...除非对象是数组的一部分

malloc是一个转移注意力的话题(还有另一组问题)。他的代码使用new[]这样malloc只是在这里毒害井。

他在幻灯片中提到的具体问题是,double在 上创建的对象buffer是由 创建的std::uninitialized_default_construct_n,并且此方法不会创建双精度数组,而是创建在内存中连续的多个对象。他断言,在 C++ 标准(您正在编程的抽象机)中,您不能将对象视为数组的一部分,除非您实际创建了对象数组。

作者试图指出的一点是,C++ 标准存在缺陷,并且没有严格一致的方法来创建灵活的数组(C++20 之前)。


供参考的是代码(在图像后复制):

struct header
{
    int size;
    byte* buffer;
    thing some;
};
Run Code Online (Sandbox Code Playgroud)
constexpr size_t x = ...;

byte* buffer = new byte[x + n * sizeof(double)];
header* p = new (buffer) header{n, buffer};
uninitialized_default_construct_n(
    reinterpret_cast<double*>(buffer + x), n);
double* data = reinterpret_cast<double*>(p->buffer + x);

data[0] = data[1] + data[2]; // <-- problem here
                             // because we never created an array of doubles
Run Code Online (Sandbox Code Playgroud)