C++笔记121118

这里谈一下后自增操作符++

其实现在任何一个见过++i;和i++;的人都明白它的初步原理是啥。很多程序员都会说出下面这段话:

前自增代表先自增再操作,后自增代表先操作后自增。

这个先和后的说法实际上并不准确,例如下面这个程序:

 1 #include<list>
 2 
 3 int main()
 4 {
 5     list<int> testlist;
 6     for(int ix=0;ix<10;++ix)testlist.push_back(ix);
 7 
 8     list<int>::iter = testlist.begin();
 9     while(!testlist.empty())
10     {
11         testlist.erase(iter++);
12         //wrong code:
13         //testlist.erase(iter);iter++;
14     }
15     return 0;
16 }

这段程序定义了一个装有int型数据的list容器,然后用0~9赋值。最后删除。

关键在于中间这一句怎么理解

testlist.erase(iter++);

如果按照“先操作再自增”的解释,那么似乎是先把iter所指的数据删除,然后iter指向下一个数据。但这是错误的。因为如果不用这一行,而改写成12~13行的样子,运行时会报错。原因就在于erase操作将导致指向list的迭代器iter失效。这时再写iter++就没有任何意义。

那么为什么testlist.erase(iter++)确是正确的呢?原因在于后自增操作符并不是简单的“先操作再自增”。实际上首先注意iter++是一个表达式,任何一个表达式都有一个返回值,而后自增表达式的返回值既不是iter+1也不是iter本身,而是尚未自增的iter的副本。换句话说,iter++这个表达式实际上做了三个操作:

1、构造一个iter的原来的值的副本。

2、iter自增1。

3、返回那个副本。

所以erase(iter++)操作的其实是iter原来值的副本,而且操作是在最后一步进行的。所以失效的是副本迭代器,而iter由于已经在第二步自增指向了下一个元素,所以没有问题。

而如果分开来写就不行了,因为erase(iter)后,iter已然失效,成为了悬垂的迭代器,这时再iter++是没有意义的。

虽然博主并不推崇谭浩强把i++,++i搞得错综复杂浪费时间。但是在这个问题中,出于安全性的考虑,这个细节还是重要的。当然,更常见的写法是:

iter = testlist.erase(iter);

这里用到erase()函数会返回一个指向被删除元素的下一元素的迭代器,并用它重新给iter赋值。但从可读性上来说,博主个人更加喜欢erase(iter++)的表达。

另外,从上述例子中可以看出来的是,iter++比++iter做的事情更多。对于简单的迭代器差别不大,但是对于复杂的迭代器类型,iter++是比++iter开销大的。从返回值上来说,iter++返回的是一个右值(副本),而++iter返回的是一个左值(自增后的iter本身)。如果没有特殊需要,仅仅想要自增的话,正如C++ Primer中所推荐的那样,最好通常只用前自增操作符。这就是为什么C++程序员在循环中都喜欢写++i而不是i++的原因。

posted @ 2012-11-18 18:34  hilbertan  阅读(241)  评论(0编辑  收藏  举报