C++ 迭代一项 - UB 或定义的行为



我最近一直在思考 c++ 中指针算术的规则,了解到指针算术只为指向数组中存在的对象的指针定义。

这让我怀疑以下代码的行为是否严格未根据标准定义。

谁能透露任何光芒?

#include <iostream>
#include <algorithm>
#include <iterator>
#include <utility>
#include <string>
#include <vector>
struct Thing {
    std::string val;
};
int main() {
    Thing a_thing;
    std::vector<Thing> things;
    // take address
    auto first_thing = std::addressof(a_thing);  
    // take address of "one past the end" - UB?
    auto last_thing = std::next(first_thing);    
    // copying exactly one item, but is it UB?
    std::copy(first_thing, last_thing, std::back_inserter(things));  
}

根据 5.7 [expr.add] 第 4 段,指向对象的指针的行为类似于单元素数组的第一个对象的指针:

出于这些运算符的目的,指向非数组对象的指针的行为与指向长度为 1 的数组的第一个元素的指针的行为相同,并将对象的类型作为其元素类型。

正如其他答案提到的,您的程序格式良好。以下是最新工作文件中的相关标准:

§5.7 (脚注 86) [补充]

为此目的,非数组元素

的对象被视为属于单元素数组;请参阅 [expr.unary.op]。经过数组x n元素的最后一个元素的指针被视为等效于指向为此目的x[n]的假设元素的指针;参见[基本化合物]。

简而言之,非数组对象的行为类似于指针算术上下文中的单元素数组。因此,采用"一个过去"的地址是合法的。

这是

格式正确的。

[expr.add]/4 指出:

出于这些运算符的目的,指向非数组对象的指针的行为与指向长度为 1 的数组的第一个元素的指针的行为相同,并将对象的类型作为其元素类型。

之后声明([expr.add]/5):

如果指针操作数和结果都指向同一数组对象的元素,或者一个过去 数组对象的最后一个元素,求值不得产生溢出;否则,行为为 定义。

强调我的。

程序格式良好。

您可以设置一个指针超过数组的末尾,甚至刚好超出标量地址,就好像它是一个单元素数组一样。

第二部分在这里很重要。只要你实际上没有取消引用last_thingstd::copy不会,你的代码就会完美运行。

最新更新