• 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 <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);//调用后置
    这个是约定俗成



  • 相关阅读:
    【InteillJ IDEA】Git的安装+同步项目到GitHub上
    【GitHub】给GitHub上的ReadMe.md文件中添加图片怎么做 、 gitHub创建文件夹
    【Linux】CentOS7上解压zip需要安装uzip
    【Linxu】CentOS7下安装程序报错:
    【linux】CentOS编译程序报错 修复 ./Modules/_ssl.c:64:25: 致命错误:openssl/rsa.h:没有那个文件或目录
    【redis】4.spring boot集成redis,实现数据缓存
    【报错】spring整合activeMQ,pom.xml文件缺架包,启动报错:Caused by: java.lang.ClassNotFoundException: org.apache.xbean.spring.context.v2.XBeanNamespaceHandler
    【报错】项目启动部署时报错:java.lang.NoSuchMethodError
    【IntelliJ idea/My/ecplise】启动项目前,修改配置JVM参数
    Java 读写文件大全
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5159671.html
Copyright © 2020-2023  润新知