首页 > 解决方案 > c++ 11: &v[0] 在空的 std::vector v 上

问题描述

如果我有一个有时可能为空的 std::vector v ,是 g++ 纯属运气,我可以用 &v[0] 获得指向这个不存在数据的指针,还是我会得到其他编译器的段错误(我的 g++ 对以下内容很好,并且在实际运行中从未给出过段错误)。

std::vector<int> v = {}; std::cout << (&v[0] == NULL) << std::endl; // true with my g++

谢谢

标签: c++pointers

解决方案


是的,您的代码具有未定义的行为。

v[0]调用一个返回的函数int&,并且没有“空引用”,所以&v[0]一开始就永远不能为 NULL。这就是为什么带有优化的 clang 会打印您的代码0,并将以下内容优化为return false;

bool is_pointer_to_first_null(std::vector<int>& v) {
    return &v[0] == nullptr;
}

(哪个clang也警告你)

它还破坏了std::vector<T>::operator[](n)定义为等效于的合同*(v.begin() + n),并且由于v.begin() + 0 == v.begin() == v.end()对于空向量,这不是可取消引用的迭代器,并且您的标准库实现可以做任何事情。
例如,使用已定义,这将使用 g++_GLIBCXX_DEBUG打印。Error: attempt to subscript container with out-of-bounds index 0, but container only holds 0 elements.https://godbolt.org/z/anran5

在 gcc 中&v[0] == nullptr未优化的事实是错过了优化。false也许&v[0]已经优化到v.data()first 并且 this 为非 null 的信息丢失(或出于任何原因不使用)。
如果没有优化,gcc 将很乐意形成空引用,因为引用是作为指针实现的,并且&reference在汇编中是一个 noop。对于大多数架构上的大多数编译器来说都是如此,因此这不太可能出现段错误。


也许您正在寻找v.empty()(它仍然可以有一个非空数据指针)、v.data() == nullptr(当定义时v.data() == &v[0]),或者v.capacity() == 0?不过,不应该有充分的理由检查数据指针是否为空。


推荐阅读