关于++操作符

一件小事

       事情是这么开始的,首先某个业务模块结果出现错误,与原结果对比不一致。检查了一下,是PCLint整改过程中,某人修改了下列代码(大概类似,便于理解,稍微改造一下,代码写的如何不做评论),原有代码:

std::list intList;
…;
std::list::iterator curItr = intList.begin();
std::list::iterator preCurItr = curItr++;
for (; curItr != intList.end(); preCurItr = (curItr++)) {
    …;
}

        PCLint整改后代码(仅for循环部分):

for (; curItr != intList.end(); curItr++) {
    preCurItr = curItr++;
    …;
}

        这代码明显逻辑错误,于是,我便修正为以下代码(PCLint问题可能会重新存在,先不予考虑):

for (; curItr != intList.end(); preCurItr = curItr++) {
    …;
}


有问题吗?

        先不看后文,自己思考一下,修改后的代码有问题吗?

        对比原有代码和我修改后的代码,可以非常明显看出for循环中缺少一个括号,于是我便认为:括号的优先级比较高,会先进行括号内部的运算,然后在进行赋值运算,那岂不是两个迭代器指向同一个元素了吗?

 

一个字:试!

        由于原代码作者已经离职,原代码又没有任何问题,我便怀疑是算法本来就是这样?仔细思考了一下,又根据上下文代码推断了一下,确定了算法肯定不会这么执行的。于是乎,只能尝试一下这个到底有没有问题了,尝试的结果就是写下以下测试代码:

std::vector intVec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::vector::iterator curItr = intVec.begin();
std::vector::iterator preCurItr = curItr++;
for (; curItr != intVec.end(); preCurItr = curItr++) {
    std::cout << “curItr: “ << *curItr << “ preCurItr: “ << *preCurItr << std::endl;
}
curItr = intVec.begin();
preCurItr = curItr++;
for (; curItr != intVec.end(); preCurItr = (curItr++)) {
    std::cout << “curItr: “ << *curItr << “ preCurItr: “ << *preCurItr << std::endl;
}

        结果果真是完全一样的,以我的个性,肯定要打破铁锅问到底呐。


操作符 - 函数

        身边的宁哥突然来了一句,++操作符就是这么实现的,跟括号有什么关系。真是“众里寻他千百度,蓦然回首,那人却在灯火阑珊处”啊。

        是啊,仔细想想,就是一个操作符而已,后置++操作符的实现大概过程如下:

int tmp = *this;
++*this;
return tmp;

        无论加不加括号,return的值永远都是tmp,实际上跟括号没有半毛钱关系啊。实际上操作符的实现不也就是一个函数吗?换个角度考虑一下不就豁然开朗了吗?

 

进一步思考

        学而不思则罔,思而不学则殆。我总是犯一些很二的问题,所以要记得时时刻刻进行总结,否则几年之后还在纠结这些东西,就真是贻笑于大方之家了。

        顺着刚才的劲头,于是乎写下了以下代码:

class A
{
public:
    A() 
    {
        std::cout << “Constructor” << std::endl;
    }

    A(const A &) 
    {
        std::cout << "Copy Constructor" << std::endl;
    }

    A &operator=(const A &) 
    {
        std::cout << "Copy" << std::endl;
        return *this;
    }

    A &operator++() 
    {
        std::cout << "Pre Plus" << std::endl;
        return *this;
    }

    A operator++(int) 
    {
        std::cout << "Post Plus" << std::endl;
        A tmp = *this;
        ++*this;
        return tmp;
    }
};

int main()
{
    A a;
    A b = a++;
    A c = (a++);
    return 0;
}

        深入理解一下,有这么几个关键点:

        1. ++操作符优先级大于赋值操作符=,即使不考虑后置++的返回值,a++与(a++)也是完全一致的,当然此处跟操作符优先级没有关系,只是稍微思考一下。

        2. C++编译器识别函数是否同名,主要使用(函数名_参数类型)方式,所以后置++多一个int型参数实际上只是为了区别用,没有任何实际意义,另外,int后不要定义参数名称,否则编译器会报warning:此参数没有被使用。

        3. 前置++和后置++的返回值类型要注意区别,另外后置++内部实际上是调用前置++,这个有效率消耗,尤其是自定义类型不会被编译器优化时(这个在Debug模式下体现很明显,尤其是迭代器)。

        4. 在同一条语句里面不能修改同一个变量一次以上,否则会造成未定义错误。例如:

int a = 0;
a = a++;

       这样写有些编译器会在编译期间报出未定义的warning,有些编译器会在程序执行期间产生错误值,需要注意。

       5.摒除一切罪恶的根源就是:不要写出让人难以理解的代码。当然在一些效率问题上可能会有例外,不过那也是一种美,叫做短码之美。但是大部分代码还做不到这种“美”,那就写“可维护的代码”吧!

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值