一:今天做poj上的3750那个题,用到了list的erase方法。提交之后总是报runtime error!

纠结了好长时间。曾有一度怀疑过vector的erase和list的erase处理方式不一样。理论知识请參考也指针和悬浮指针:http://blog.csdn.net/u010700335/article/details/39831293 或 深拷贝和浅拷贝点击打开链接 http://blog.csdn.net/u010700335/article/details/39830425

二:现附上代码。稍后作解释

#include <iostream>
#include <cstdio>
#include <cstring>
#include <list>
using namespace std;
const int MAX_SIZE = 20; int main()
{
int n,w,s;
int i,cp;
char str[MAX_SIZE];
list<string> lists;
scanf("%d",&n);
for(i=0;i<n;i++)
{
cin >> str;
lists.push_back(str);
}
scanf("%d,%d",&w,&s);
list<string>::iterator iter;
iter = lists.begin();
while(w>1)
{
iter++;
w--;
}
cp = 1;
for(; lists.size()!=0;)
{
cp++;
if(iter == lists.end())
iter = lists.begin();
if(cp<=s)
{
iter++;
}
else
{
cout << *iter << endl;
iter = lists.erase(iter);// 由于删除iter,自己主动返回下一个元素的,vector也是一样;否则ter成为野指针。而非自己主动指向下一个,是返回下一个。
cp = 1;
}
}
return 0;
}

三:原因例如以下:

程序里面使用了list容器,今天搞清楚了erase()函数的机理。经常使用的删除容器中元素的方法是例如以下(方法1):

      list< int> List;

      list< int>::iterator iter;

      for( iter = List.begin(); iter != List.end(); )

      {

            if(1)  

            {

               iter = List.erase( iter );

            }

            else

            {

               iter++;

            }

      }





      也能够这样写(方法2):

      list< int> List;

      list< int>::iterator iter;

      for( iter = List.begin(); iter != List.end(); )

      {

            if(1)  

            {

               List.erase( iter++ );

            }

            else

            {

               iter++;

            }

      }





     有一种错误的写法(注意同方法2比較)

     list< int> List;

     list< int>::iterator iter;

     for( iter = List.begin(); iter != List.end(); )

     {

            if(1)  

            {

               List.erase( iter );

            }





            iter++;

     }// 



     我们看一下erase()函数的源码(仅列出release下的代码)。



        iterator erase(iterator _Where)

        {    // erase element at _Where

        _Nodeptr _Pnode = (_Where++)._Mynode();





        if (_Pnode != _Myhead)

            {    // not list head, safe to erase

            _Nextnode(_Prevnode(_Pnode)) = _Nextnode(_Pnode);

            _Prevnode(_Nextnode(_Pnode)) = _Prevnode(_Pnode);

            this->_Alnod.destroy(_Pnode);

            this->_Alnod.deallocate(_Pnode, 1);

            --_Mysize;

            }

        return (_Where);

        }



函数在返回的时候,是返回当前迭代器的下一个节点。所以当 iter = List.erase( iter ); 运行以后。迭代器自己主动指向了下一个元素。

而对于入參中的iter。所指的地址已经被销毁,所以写的时候,应该注意加上前面的iter =



四:iter++ 和 ++iter

那另外的一种写法,List.erase( iter++ ); 为什么也是对的呢?这里研究了一下,这里须要讲一下++运算符的操作。



        _Myt_iter& operator++()   // 前面自增

            {    // preincrement

            ++(*(_Mybase_iter *)this);

            return (*this);

            }





        _Myt_iter operator++(int) // 后面自增

            {    // postincrement

            _Myt_iter _Tmp = *this;

            ++*this;

            return (_Tmp);

            }





++实际上能够看做是一个函数。

对于++在后的情况(比如i++),函数在执行的时候,将运算的数据i已经改变。可是函数的返回值是操作之前的数据。所以在我们看来,i++好像是先进行了i的读取。才+1。

回到迭代器,List.erase( iter++ );就没有问题了。

对于那种错误的方法,List.erase( iter );在运行以后,iter所指的对象已经被销毁,所以再对iter进行操作是非法的,程序会出错。

再看一个简单的演示样例:

#include <iostream>
using namespace std;
class A
{
public:
A(int a=0,int b=0)
{
x=a;
y=b;
}
A& operator++();
A operator++(int);
void out()
{cout<<x<<","<<y<<endl;
}
private:
int x,y;
};
A& A::operator++()
{
x++;
y++;
return *this;
}
A A::operator++(int)
{
return *this;
x++;
y++;
}
void main()
{
A ta(1,2),tb(1,2);
ta.out();
tb.out();
(++ta).out();
(tb++).out(); }
依据书上的形式写了个程序,A&前置和A型后置,程序正确,就是有个疑问:
为什么编译器会自己主动调用A&型。A型。它怎么知道在++号在ta前面时。要调用A&;++号在ta后面时,要调用A;到底是怎么办到的?

重载的++ 符号在使用过程中 编译器是不能区分出 ++是前置的还是 后置的?是依据(int)来区分 当给定实參(比方0)时为后置

opertor++();//重载前置++

operator++(int); //重载后置++




c.opertor++;//调用前置

c.opertor++(0);//调用后置

这个是约定俗成

c++野指针 之 实战篇的更多相关文章

  1. ArcGIS制图表达Representation实战篇3-控制点

    ArcGIS制图表达Representation实战篇3-控制点 by 李远祥 这一章讲述的是一个非常专业的名词,叫控制点.此控制点非测绘行业术语的控制点,而是制图表达里面的控制点,所以不能混为一谈. ...

  2. SQL Server ->> 高可用与灾难恢复(HADR)技术 -- AlwaysOn(实战篇)之建立活动目录域、DNS服务器和Windows故障转移群集(准备工作)

    因为篇幅原因,AlwaysOn可用性组被拆成了两部分:理论部分和实战部分.而实战部分又被拆成了准备工作和AlwaysOn可用性组搭建. 三篇文章各自的链接: SQL Server ->> ...

  3. C程序疑问解答 ——可怕的野指针

    本篇为原创,禁止任何形式的他用! 一.疑问点         指针是C语言一个很强大的功能,同时也是很容易让人犯错的一个功能,用错了指针,轻者只是报个错,重者可能整个系统都崩溃了.下面是大家在编写C程 ...

  4. "迷途"的野指针,都快找不着北了

    指针,C语言开发者表示很淦,指针的使用,很多人表示不敢直面ta,不像Java一样,有垃圾自动回收功能,我们不用担心那么多内存泄漏等问题,那C语言里边呢,指针又分为了"野指针",&q ...

  5. 二、Redis基本操作——String(实战篇)

    小喵万万没想到,上一篇博客,居然已经被阅读600次了!!!让小喵感觉压力颇大.万一有写错的地方,岂不是会误导很多筒子们.所以,恳请大家,如果看到小喵的博客有什么不对的地方,请尽快指正!谢谢! 小喵的唠 ...

  6. linux kernel elv_queue_empty野指针访问内核故障定位与解决

    1. 故障描述 故障操作步骤: 单板上插了一个U盘,出问题前正在通过FTP往单板上拷贝文件,拷贝的过程中单板自动重启. 故障现象: Entering kdb (current=0xc000000594 ...

  7. iOS为真机调试增加scribble来定位野指针

    尽管在ARC中,野指针出现的频率已经大大降低了,但是仍然会有野指针困扰着我们. 在模拟器调试中,我们可以开启scribble或者zombieObject来将已经释放的内存填充无意义的内容,能够将一些非 ...

  8. C++内存泄露之野指针

    写出本文仅仅是处于备忘的目的. 最近为现在做的软件添加了一个内存回收机制(以前处于某种内存只申请不释放,这并不等于内存泄露,因为我们知道这些内存块在内存中的位置)-- 在某一块内存不使用的时候将其释放 ...

  9. iOS开发_内存泄漏、内存溢出和野指针之间的区别

    今天,在工作群中,被问到了内存泄漏和野指针指向的区别,自己答的不是很好,特意回来查了资料,在博文中总结一下经验,欢迎指正. 内存泄漏:是指在堆区,alloc 或new 创建了一个对象,但是并没有放到自 ...

随机推荐

  1. Android插件化开发---执行未安装apk中的Service

    欢迎各位增加我的Android开发群[257053751​] 假设你还不知道什么叫插件化开发.那么你应该先读一读之前写的这篇博客:Android插件化开发,初入殿堂 上一篇博客主要从总体角度分析了一下 ...

  2. cookie的path和domain參数实例解析

    一句话概括两个參数含义各为: path表示cookie所在的文件夹 domain表示的是cookie所在的域,默觉得请求的地址 首先改动我们的 hosts 文件 我本机内网ip 192.168.1.1 ...

  3. vim 操作指令1

    1.vim 在命令行中输入vim,进入vim编辑器 2.i 按一下i键,下端显示 –INSERT–插入命令,在vim中可能任意字符都有作用 3.Esc 退出i(插入)命令进行其它命令使用 4.:r f ...

  4. 【ASP.NET Web API教程】2.3.3 创建Admin控制器

    原文:[ASP.NET Web API教程]2.3.3 创建Admin控制器 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. Part 3 ...

  5. Vmdk文件如何使用,vmdk导入虚拟机VMware8.0教程

    一.打开虚拟机VMware Workstation8.0,点击新建虚拟机. 二.进入虚拟机向导,选择自定义. 三.这里保持默认即可. 四.这里选择“我以后安装操作系统”. 五.这里选择Windows ...

  6. input在苹果浏览器下变成圆角的解决方案

    复制代码代码如下: .form-actions input{ ... -webkit-appearance: none; } 更新到iPhone一看,真爽,问题解决了.

  7. OSGi 学习之路(4) - osgi的模块化 java在模块化的局限性

    底层代码可见性控制 Java提供了private,public,protected和package private(无修饰符)这四种访问控制级别,不过这仅仅提供了底层的OO数据封装特性.包这个概念确实 ...

  8. iOS开发经常使用宏定义

    iOS开发经常使用宏定义 iOS开发中经常须要获取屏幕宽度高度,为view设置颜色,为imgagView设置图片等,我们都可定义一些宏,随时都可拿来使用,方便开发 <span style=&qu ...

  9. Phpcms V9 所有的中文变量

    $LANG['start_update_category'] = '开始更新栏目页 ...'; $LANG['start_to_end_id'] = '" 第{page} - {endpag ...

  10. windows系统port监听

    通常情况下.假设想发现全部已经使用的和正在监听的port,我们能够使用netstat命令. netstat并不是一个port扫描工具.假设你想扫描计算机开放了哪些port的话.建议使用本文介绍的方法. ...