无效的指针算术

指针算法的以下用法会导致未定义的行为:

  • 如果结果不属于与指针操作数相同的数组对象,则添加或减去整数。 (这里,结尾的元素被认为仍然属于数组。)

    int a[10];
    int* p1 = &a[5];
    int* p2 = p1 + 4; // ok; p2 points to a[9]
    int* p3 = p1 + 5; // ok; p2 points to one past the end of a
    int* p4 = p1 + 6; // UB
    int* p5 = p1 - 5; // ok; p2 points to a[0]
    int* p6 = p1 - 6; // UB
    int* p7 = p3 - 5; // ok; p7 points to a[5]
    
  • 如果它们不属于同一个数组对象,则减去两个指针。 (同样,超过结尾的元素被认为属于数组。)例外是可以减去两个空指针,产生 0。

    int a[10];
    int b[10];
    int *p1 = &a[8], *p2 = &a[3];
    int d1 = p1 - p2; // yields 5
    int *p3 = p1 + 2; // ok; p3 points to one past the end of a
    int d2 = p3 - p2; // yields 7
    int *p4 = &b[0];
    int d3 = p4 - p1; // UB
    
  • 如果结果溢出 std::ptrdiff_t,则减去两个指针。

  • 任何指针运算,其中操作数的指针类型与指向的对象的动态类型不匹配(忽略 cv-qualification)。根据标准,“[特别是,当数组包含派生类类型的对象时,指向基类的指针不能用于指针算术。”

    struct Base { int x; };
    struct Derived : Base { int y; };
    Derived a[10];
    Base* p1 = &a[1];           // ok
    Base* p2 = p1 + 1;          // UB; p1 points to Derived
    Base* p3 = p1 - 1;          // likewise
    Base* p4 = &a[2];           // ok
    auto p5 = p4 - p1;          // UB; p4 and p1 point to Derived
    const Derived* p6 = &a[1];
    const Derived* p7 = p6 + 1; // ok; cv-qualifiers don't matter