linux+c野指针+工具,c++野指针 之 实战篇

一:今天做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

#include

#include

#include

using namespace std;

const int MAX_SIZE = 20;

int main()

{

int n,w,s;

int i,cp;

char str[MAX_SIZE];

list lists;

scanf("%d",&n);

for(i=0;i

{

cin >> str;

lists.push_back(str);

}

scanf("%d,%d",&w,&s);

list::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

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<

}

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);//调用后置

这个是约定俗成

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值