鱼C论坛

 找回密码
 立即注册
查看: 1448|回复: 4

[已解决]类标准库的使用

[复制链接]
发表于 2019-1-25 11:33:20 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main()
{
       
        vector<int> lst = {1,101,2,303,4,404,6,707,9,909,1001};
        auto it = lst.begin();
        while(it != lst.end())
        {
                if (*it %2)
                {
                        lst.erase(it);    # 在这一行  C++primer中的书写方式是 it = lst.erase(it);
                }
                else
                {
                        ++it;
                }
        }
        for (auto it1 = lst.begin() ; it1 != lst.end();++it1)
        {
                cout << "####################" << endl;
                cout << *it1 << endl;
                cout << "####################" << endl;
        }
        return 0;
}

question:
不写it = 的方式和书写了的方式有何不同? 为什么要写上那一步?
最佳答案
2019-1-25 14:00:47
对于某些比较宽松的编译器,按现版本的vector存储方式,确实结果应该是一样的,
但这只对vector等少数基于数组存储的容器有效,且仅在某些比较宽松的编译器中有效,(在vs 2017中会报错)


需要解释的话,首先了解一下vector是如何存储元素的
作为一个变长数组,当向其存储数据时,vector会申请一段默认长度的空间,比方说,对于一个储存了{1,2,3}的vector,它内部可能是这样的
{1,2,3,0},size=3;这个时候,向其添加一个元素4,它会变成这样{1,2,3,4},size=4,这个时候,1,2,3的地址都没有改变,那么指向其的指针均保持有效;
但是,这个时候再向其添加一个元素5,因为原来的数组已经不够大,vector会申请一段更大的空间,比如int[8],并把原来的元素搬过去,就变成了这样
{1,2,3,4,5,0,0,0},size=5;这个时候,指向原1,2,3的指针,其地址已经被释放,也就是变成了野指针。
但是现版本的vector,在删除元素时,并不会发生容量的减少,所以指针总是有效;

但是,迭代器并不仅仅是指针,而是包装了的指针,当你调用erase(it)时,it会直接被标记为“失效”,因而对于某些编译器,会因为你调用了“失效”了的迭代器而报错,
此外,你并不能保证,在下个版本中,vector不会因为erase而减少容量;
第三,对于其他容器,比如基于链表的容器,这种用法一定失败。

因此,即使在这个例子中成功了,你也不应该试图调用一个失效了的迭代器

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-1-25 12:01:32 | 显示全部楼层
本帖最后由 Croper 于 2019-1-25 12:21 编辑

erase返回的是指向被删除元素后面的那个位置,
如对于{1,2,3,4},此时it指向2,那么erase(it),原来的vector变成{1,3,4},并且erase返回一个指向3的迭代器,

如果不写it=的话,
那么你erase(it)之后,it就成为了野指针(野迭代器?),之后的操作会全部失效
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-1-25 13:20:15 | 显示全部楼层
Croper 发表于 2019-1-25 12:01
erase返回的是指向被删除元素后面的那个位置,
如对于{1,2,3,4},此时it指向2,那么erase(it),原来的vector ...

然而得到的结果是一样的 我试了下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-1-25 14:00:47 | 显示全部楼层    本楼为最佳答案   
对于某些比较宽松的编译器,按现版本的vector存储方式,确实结果应该是一样的,
但这只对vector等少数基于数组存储的容器有效,且仅在某些比较宽松的编译器中有效,(在vs 2017中会报错)


需要解释的话,首先了解一下vector是如何存储元素的
作为一个变长数组,当向其存储数据时,vector会申请一段默认长度的空间,比方说,对于一个储存了{1,2,3}的vector,它内部可能是这样的
{1,2,3,0},size=3;这个时候,向其添加一个元素4,它会变成这样{1,2,3,4},size=4,这个时候,1,2,3的地址都没有改变,那么指向其的指针均保持有效;
但是,这个时候再向其添加一个元素5,因为原来的数组已经不够大,vector会申请一段更大的空间,比如int[8],并把原来的元素搬过去,就变成了这样
{1,2,3,4,5,0,0,0},size=5;这个时候,指向原1,2,3的指针,其地址已经被释放,也就是变成了野指针。
但是现版本的vector,在删除元素时,并不会发生容量的减少,所以指针总是有效;

但是,迭代器并不仅仅是指针,而是包装了的指针,当你调用erase(it)时,it会直接被标记为“失效”,因而对于某些编译器,会因为你调用了“失效”了的迭代器而报错,
此外,你并不能保证,在下个版本中,vector不会因为erase而减少容量;
第三,对于其他容器,比如基于链表的容器,这种用法一定失败。

因此,即使在这个例子中成功了,你也不应该试图调用一个失效了的迭代器

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-1-25 14:06:50 | 显示全部楼层
Croper 发表于 2019-1-25 14:00
对于某些比较宽松的编译器,按现版本的vector存储方式,确实结果应该是一样的,
但这只对vector等少数基于 ...

十分感谢您的回复
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-10-3 06:26

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表