memmove正在复制0个字节,但引用超出界限是否安全

Is memmove copying 0 bytes but referencing out of bounds safe

本文关键字:引用 出界 界限 安全 是否 复制 0个 字节 memmove      更新时间:2024-09-23

我在网上读到,如果要复制的字节数为0,则memmove预计不会执行任何操作。然而,我想知道的是,在这种情况下,是否预期不会读取源指针和目标指针

下面是我的一些代码的简化版本,我感兴趣的部分是shiftLeft:

#include <array>
#include <cstring>
#include <iostream>
class Foo final {
unsigned just       = 0;
unsigned some       = 0;
unsigned primitives = 0;
};
template <unsigned Len>
class Bar final {
unsigned             depth = 0;
std::array<Foo, Len> arr;
public:
Bar() = default;
// Just an example
void addFoo() {
arr[depth] = Foo();
depth++;
}
void shiftLeft(unsigned index) {
// This is what my question focuses on
// If depth is 10 and index is 9 then index + 1 is out of bounds
// However depth - index - 1 would be 0 then
std::memmove(
&arr[index],
&arr[index + 1],
(depth - index - 1) * sizeof(Foo)
);
depth--;
}
};
int main() {
Bar<10> bar;
for (unsigned i = 0; i < 10; ++i)
bar.addFoo();
bar.shiftLeft(9);
return 0;
}

Len10depth10,并且index9时,则index + 1将读出越界。然而,在这种情况下,depth - index - 1也是0,这应该意味着memmove将不执行任何动作。这个代码安全吗?

memmove函数将复制n字节。如果n为零,它将不起任何作用。

唯一可能的问题是,其中index已经达到数组元素的最大值:

&arr[index + 1]

但是,您可以引用数组中的数组元素(指针指向它们(,也可以引用数组末尾以外的假设元素

您可能不会取消引用后者,但您在这里没有这样做。换句话说,虽然arr[index + 1]本身会尝试取消引用,因此是无效的,但评估其地址是可以的。

这在C++20 [expr.add]:中有所涉及,尽管是切向的

将具有整型的表达式添加到指针或从指针中减去时,结果具有指针操作数的类型。如果表达式P指向具有n元素的阵列对象x的元素x[i],则表达式P + JJ + P(其中J具有值j(指向(可能假设的(元素x[i + j] if 0 ≤ i + j ≤ n;否则,行为是未定义的。

注意if 0 ≤ i + j ≤ n子句,特别是最后一个。对于数组int x[10],表达式&(x[10])是有效的。

[basic.compound](我的重点(:也涵盖了这一点

指针类型的值是指向或超过对象末尾的指针,该值分别表示对象占用的内存中第一个字节的地址,或对象占用的存储结束后内存中的第一个字节。