使用 std::vector,为什么 &vec[0] 未定义的行为,而 vec.data() 是安全的?

With std::vector, why is &vec[0] undefined behavior, but vec.data() safe?

本文关键字:vec data 安全 为什么 vector std 使用 未定义      更新时间:2023-10-16

我一直在阅读 isocpp.org"链接此处"的常见问题解答,并遇到了警告,并std::vector

std::vector<int> v;
auto a = &v[0]; // Is undefined behaviour but
auto a = v.data(); // Is safe

从实际站点:

void g()
{
std::vector<Foo> v;
// ...
f(v.begin(), v.size());  // Error, not guaranteed to be the same as &v[0]
↑↑↑↑↑↑↑↑↑ // Cough, choke, gag; use v.data() instead
}

此外,&v[0]如果std::vectorstd::array是空的,而使用.data()始终是安全的 功能。

我不确定我是否完全理解了这一点。::data()返回指向数组开头的指针,&[0]返回开头的地址。我在这里没有看到区别,而且我不认为&[0]正在取消引用任何东西(即,没有读取元素 0 的内存)。在调试版本中的Visual Studio上,访问下标[0]会导致断言失败,但在发布模式下,它不会说什么。此外,对于默认构造的向量,这两种情况下的地址均为 0。

我也不明白关于::begin()不能保证与::operator[0]相同的评论.我假设对于向量,begin()迭代器中的原始指针、::data()&[0]都是相同的值。

我在这里看不到区别

&v[0]&(v[0])相同,即从v的第 1 个元素获取地址。但是当v为空时,根本没有元素,v[0]只会导致 UB,它试图返回一个不存在的元素;试图从中获取地址是没有意义的。

v.data()始终是安全的。它将直接返回指向基础数组的指针。当v为空时,指针仍然有效(它可能为空指针,也可能不是空指针);但请注意,取消引用它(如*v.data())也会导致 UB,与v[0]相同。

我也不明白关于::begin()不能保证与::operator[0]相同的评论

std::vector::begin将返回一个类型为std::vector::iterator的迭代器,它必须满足 RandomAccessIterator 的要求。它可能是一个原始指针,但不一定是。将其作为一个类实现是可以接受的。

为了使您的示例更易于理解,您的问题中缺少的信息是void f(Foo* array, unsigned numFoos);Foo向量上调用.begin()不能保证是一个指针。但是有些实现的行为可能足够像它,使其工作。

在空向量情况下,v.data()返回一个指针,但您不知道它指向什么。它可能是一个空点,但这不能保证。

这一切都归结为一件简单的事情:您可以向指针添加或减去整数值,但尝试取消引用无效指针是未定义的行为。

比如说,

int a[10];
int* p = a;
int* q = p + 10;   // This is fine
int r = *(p + 10)  // This is undefined behaviour

在您的示例中:v[0]*(v's internal pointer+0)相同,如果向量为空,这是一个问题。