提问人:Zebrafish 提问时间:1/7/2018 最后编辑:Peter MortensenZebrafish 更新时间:1/8/2018 访问量:3324
使用 std::vector,为什么 &vec[0] 未定义的行为,而 vec.data() 是安全的?
With std::vector, why is &vec[0] undefined behavior, but vec.data() safe?
问:
我一直在阅读 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
}
此外,如果 or 为空,则使用是未定义的行为,而使用该函数始终是安全的。
&v[0]
std::vector
std::array
.data()
我不确定我是否完全理解了这一点。 返回指向数组开头的指针,并返回开头的地址。我在这里没有看到区别,我不认为这是取消引用任何东西(即,没有读取元素 0 的内存)。在调试版本的 Visual Studio 上,访问下标会导致断言失败,但在发布模式下,它不会显示任何内容。此外,对于默认构造向量,这两种情况下的地址都是 0。::data()
&[0]
&[0]
[0]
另外,我不明白关于不保证与.我假设对于向量,迭代器中的原始指针 和 都是相同的值。::begin()
::operator[0]
begin()
::data()
&[0]
答:
我看不出这里的区别
&v[0]
与 相同,即从 的第一个元素中获取地址。但是当是空的时,根本没有元素,只是导致 UB,它试图返回一个不存在的元素;试图从中获取地址是没有意义的。&(v[0])
v
v
v[0]
v.data()
始终是安全的。它将直接返回指向基础数组的指针。当为空时,指针仍然有效(它可能是空指针,也可能不是空指针);但请注意,取消引用它(如 )也会导致 UB,与 相同。v
*v.data()
v[0]
我也不明白关于不保证与
::begin()
::operator[0]
std::vector::begin
将返回一个类型为 std::vector::iterator
的迭代器,该迭代器必须满足 RandomAccessIterator 的要求。它可能是一个原始指针,但不一定是。将其作为一个类实现是可以接受的。
评论
operator&
vector
v.data()
为了使示例更易于理解,您的问题中缺少的信息是,调用您的向量并不能保证是指针。但某些实现可能表现得足够像它,使其能够正常工作。void f(Foo* array, unsigned numFoos);
.begin()
Foo
在空向量情况下,返回一个指针,但您不知道它指向什么。它可能是一个 nullptr,但这并不能保证。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)
评论
v[0]
评论
*