【问题标题】:Access to elements of array of arrays using common iterator使用通用迭代器访问数组数组的元素
【发布时间】:2018-08-16 20:37:29
【问题描述】:

在 C++ 中是否未定义的行为 像下面的代码那样访问相邻数组中的元素?

#include <type_traits>
#include <algorithm>
#include <iterator>

int main()
{
    int a[10][10];
    static_assert(std::is_standard_layout< decltype(a) >::value, "!");
    std::fill(std::begin(*std::begin(a)), std::end(*std::prev(std::end(a))), 0);
    struct B { int b[10]; };
    B b[10];
    static_assert(std::is_standard_layout< decltype(b) >::value, "!");
    std::fill(std::begin(std::begin(b)->b), std::end(std::prev(std::end(b))->b), 0);
}

从技术上讲,我认为对于 POD 类型,以任何方式访问底层内存都是合法的,但是 std::* 的东西呢?

如果我将所有begin/end 更改为rbegin/rend 会怎样?

【问题讨论】:

  • 第二种情况,我认为不安全(ideone.com/DyHhgA)第一种,我不知道。
  • 将 c 样式的数组 int a[10][10]; 与 c++ 混合使用永远不会很好。

标签: c++ arrays stl language-lawyer


【解决方案1】:

是的,这是 UB。

来自[basic.compound]

指针类型的每个值都是以下之一:

  • 指向对象或函数的指针(该指针被称为指向对象或函数),或
  • 超过对象末尾的指针 ([expr.add]),或
  • 该类型的空指针值 ([conv.ptr]),或
  • 一个无效的指针值。

指针类型的值是指向或超过对象末尾的指针,表示该对象占用的内存中第一个字节([intro.memory])的地址或结束后的内存中第一个字节的地址分别是对象占用的存储空间。 [ 注意:超过对象末尾的指针 ([expr.add]) 不被视为指向可能位于该地址的对象类型的不相关对象。指针值在其表示的存储达到其存储持续时间结束时变为无效;见 [basic.stc]。 — 尾注 ]

还有[expr.add]/4:

当一个整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果表达式 P 指向具有 n 个元素的数组对象 x 的元素 x[i],86 表达式 P + J 和 J + P(其中 J 的值为 j)指向(可能是假设的)元素 x[i +j] 如果 0≤i+j≤n;否则,行为未定义。同样,表达式 P - J 指向(可能是假设的)元素 x[i-j] 如果 0≤i-j≤n ;否则,行为未定义。

所以&amp;a[0][0] + 10 是一个“超过对象末尾的指针”,它是第一个数组的结束指针的过去。您不能再向该指针添加一个 - 这种情况下没有定义的行为。

指针不能既是“结束”指针是“指向对象的指针”(将&amp;a[0][0] + 10 解释为&amp;a[1][0])。这是一个或另一个。

【讨论】:

  • This thread 刚刚引起了我的注意。不知道我们应该要求他们合并什么,或者只是做一个欺骗关闭。如果不合并,我倾向于将其欺骗关闭。
猜你喜欢
  • 2014-12-05
  • 2014-04-22
  • 2012-10-08
  • 2016-07-17
  • 1970-01-01
  • 2012-02-06
  • 1970-01-01
  • 2023-03-14
  • 2019-02-17
相关资源
最近更新 更多