提问人:eyelash 提问时间:9/6/2023 最后编辑:Vlad from Moscoweyelash 更新时间:9/6/2023 访问量:117
无条件创建指向向量最后一个元素的指针是否合法?
Is unconditionally creating a pointer to the last element of a vector legal?
问:
我有以下 C++ 代码:
void bar(int&);
void baz();
void foo(std::vector<int>& v) {
int* pointer_to_last = v.data() + (v.size() - 1);
if (v.size() > 0 && *pointer_to_last == 42) {
bar(*pointer_to_last);
} else {
baz();
}
}
我无条件地创建指向向量最后一个元素的指针,但只有在向量不为空时才取消引用指针。根据标准,这是否合法,或者上面的代码是否包含未定义的行为?
如果上述程序是合法的,那么以下程序是否也合法?
void bar(int&);
void baz();
void foo(std::vector<int>& v) {
int& reference_to_last = v.back();
if (v.size() > 0 && reference_to_last == 42) {
bar(reference_to_last);
} else {
baz();
}
}
回调空容器会导致未定义的行为。
所以我假设这个程序是不合法的。是否有任何用于 GCC 或 Clang 的编译器标志或任何静态分析器会针对上述代码向我发出警告?
答:
两者都是非法的。前者被UBSAN(又名)拒绝(见[expr.add]/4
-fsanitize=undefined
)
runtime error: applying non-zero offset 18446744073709551612 to null pointer
Error: attempt to access an element in an empty container.
GCC 或 Clang 是否有任何编译器标志
以上两个,加上.-fsanitize=address
-D_GLIBCXX_DEBUG
特定于 libstdc++。如果将 Clang 与 libc++ 而不是 libstdc++ 一起使用,请使用 .(它似乎需要 libc++ 17 或更高版本,它们的调试模式被破坏了一段时间。它似乎也缺乏迭代器验证。:c)-D_LIBCPP_ENABLE_DEBUG_MODE
评论
根据 C++20 标准,行为是未定义的(7.6.6 加法运算符)
(4.1) — 如果 P 的计算结果为空指针值,而 J 的计算结果为 0, 结果是 null 指针值。
(4.2) — 否则,如果 P 指向数组的数组元素 i 具有 n 个元素的对象 x (9.3.4.5),80 表达式 P + J 和 J + P (其中 J 的值为 j)指向(可能的假设)数组 x 的元素 i + j 如果 0 ≤ i + j ≤ n,表达式 P - J 指向 如果 0 ≤ i − j ≤ n,则 x 的(可能的假设)数组元素 i − j of x。
(4.3) - 否则,行为未定义
评论
if (!v.empty() && v.back() == 42) { bar(v.back()); }
v.size()-1
v.data()
back()