与 std::vector 的指针进行比较以检查相等性是否安全

Is it safe to compare to pointer of std::vector to check equality?

本文关键字:检查 是否 安全 vector std 指针 比较      更新时间:2023-10-16
一次

,我创建了一个指向std::vector的指针点,然后我对该向量进行了一些push_backreserveresize操作,在此类操作之后,将指针与该向量的地址进行比较以检查指针是否指向该向量是否安全,因为可能会有一些内存的重新分配。

例如

std::vector<int> vec;
vector<int>* pVec = &vec;
vec.reserve(10000);
assert(pVec == &vec);
vec = anotherVec;
assert(pVec == &vec);

更重要的是,将指针与 Vector 的第一个值进行比较是否安全?例如:

std::vector<int> vec(1,0);
int* p = &vec[0];
// some operation here
assert(p == &vec[0]);

正如我自己测试的那样,似乎第一种情况是安全的,而第二种情况则不是,但我不能确定。

std::vector<int> vec;
vector<int>* pVec = &vec;
vec.reserve(10000);
assert(pVec == &vec);

是安全的。


std::vector<int> vec(1,0);
int* p = &vec[0];
// some operation here
assert(p == &vec[0]);

不安全。


第一个块是安全的,因为即使其内容发生变化,地址vec也不会更改。

第二个块是不安全的,因为vec[0]的地址可能会改变;例如,当vec调整自身大小时——例如,当你向它push_back元素时。

似乎第一种情况是安全的,而第二种情况则不是

没错。 在第一种"情况"中,无论reserve调用如何,vec对象本身都保留在内存中的任何位置,这可能会将托管元素移动到动态内存的另一个区域。 这是因为可以移动元素,因此在第二种情况下指针可能不会相等。

第二种情况是安全的,只要不搬迁。如果您事先知道所需的大小并在获取指针之前使用reserve()则它是完全安全的,并且可以节省一点性能(减少一个间接级别)。

但是,例如,任何带有push_back()的添加都可能超出分配的空间并使指针无效。 std::vector经过优化,如果可能的话,会尝试在同一位置分配更多内存(因为它可以节省复制数据),但您无法确定这一点。

就此而言,您可以采用迭代器,而不是使用指针,因为向量上的迭代器的行为与指针完全相同(并且对性能没有影响),具有更多的类型安全性。

vector<int>* pVec = &vec;std::vector<int>对象的地址进行操作,该地址在作用域之前有效。 vec = anotherVec;不会更改 vec 的地址,因为这里调用了 std::vectoroperator =。因此,两个assert(pVec == &vec);都已成功通过。

int* p = &vec[0];的情况下,这取决于:请参阅Iterator invalidation

第一种情况确实是安全的,因为没有向量对象地址改变的危险。只要不发生重新分配,第二种情况是安全的(可以使用 std::vector::capacity 成员函数跟踪重新分配),否则它要么是未定义的,要么是实现定义的,具体取决于语言的版本。有关更多信息,请参阅此答案。因为在这种情况下适用相同的限制。