为什么即使没有内存重新分配,在for循环中调用push_back也不安全? [英] Why is it unsafe to call push_back in a for loop even when there is no memory reallocation?

查看:282
本文介绍了为什么即使没有内存重新分配,在for循环中调用push_back也不安全?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我阅读这篇文章时: https://stackoverflow.com/a/42448319/3336423

When I read this post: https://stackoverflow.com/a/42448319/3336423

我了解,在for循环中调用push_back是不安全的,因为:

I understand, that calling push_back in a for loop is unsafe because:

如果新的size()大于Capacity(),则所有迭代器和 引用(包括过去的迭代器)无效. 否则,只有过去的迭代器才无效.

If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.

然后,我假设如果我保证不会超出容量,那将是安全的....

Then, I assume that if I guarantee the capacity won't be exceeded, it would be safe....

但显然不是,即使我看到循环内的容量保持不变(因此我假设向量也不会重新分配其内存),在调用第一个push_back之后(使用Visual Studio),下面的所有实现都会崩溃:

But apparently not, all implementations below will crash after first push_back is called (using Visual Studio), even if I can see that capacity remains unchanged within the loop (so I assume the vector does not reallocate its memory):

版本1:

std::vector<int> v1{ 3, 4, 5 };
v1.reserve( v1.size()*2 );
size_t c1 = v1.capacity();
for ( auto val : v1 )
{
    v1.push_back( val );
    c1 = v1.capacity();
}

版本2:

std::vector<int> v2{ 3, 4, 5 };
v2.reserve( v2.size()*2 );
size_t c2 = v2.capacity();
auto curEnd = v2.end();
for ( auto iter = v2.begin(); iter != curEnd; ++iter )
{
    v2.push_back( *iter );
    c2 = v2.capacity();
}

版本3:

std::vector<int> v3{ 3, 4, 5 };
v3.reserve( v3.size()*2 );
size_t c3 = v3.capacity();
for ( auto iter = v3.begin(); iter != v3.end(); ++iter )
{
    v3.push_back( *iter );
    c3 = v3.capacity();
}

是什么使这些代码崩溃?

What makes those code crash?

推荐答案

前两个版本都存在相同的问题.第一次插入后,缓存的后端迭代器将失效,从而使其在以后无法使用.是的,甚至只是与它进行比较.

Both your first two versions have the same problem. The cached past-the-end iterator is invalidated after the first insertion, making any subsequent use of it UB. Yes, even just comparing against it.

您的第三个示例崩溃,因为最终试图重新插入新插入的元素.因此最终需要重新分配,最终导致更多的UB.

Your third sample crashes because it ends up trying to re-insert the freshly inserted elements. So it ends up needing a reallocation, which ends up causing more UB.

基于迭代器的正确方法是走到最后.但是直到最后,假设向量不为空.

The correct iterator-based approach is to not go until one past the end. But until the end, assuming the vector is not empty.

std::vector<int> v{ 3, 4, 5 };
v.reserve( v.size()*2 );

auto it = v.begin(), end = v.end();
--end;
do {
  v.push_back(*it);
} while (it++ != end); // Check against current position, but increment still

这篇关于为什么即使没有内存重新分配,在for循环中调用push_back也不安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆