zoukankan      html  css  js  c++  java
  • ++i、i++、i+=1、i=i+1的区别

    0.  写在最前面

    希望大家收藏:

    本文持续更新地址:https://haoqchen.site/2018/10/15/difference-between-++i-i++-i+=1-i=i+1/

    面试被问到,上面这四个有什么区别。总结了一下,如果觉得还不错就点个赞,点个关注呗,博主会长期更新自己的学习和收获。

    目录

    0.  写在最前面

    1. 首先对于内置类型,对于现代编译器而言,这四个的效率都是没有区别的

    2. 但是对于自定义类型,这就不一样了。

    2.1 a++与++a区别

    2.1.1 效率检测:

    2.1.2 左右值检测:

    2.2 a+=b与a=a+b的区别

    参考


    • 1. 首先对于内置类型,对于现代编译器而言,这四个的效率都是没有区别的

    我在VS2013下进行编译运行,然后调试->窗口->反汇编,查看汇编代码后发现,这四个都是一样的。。。。。

    dword 双字 就是四个字节
    ptr pointer缩写 即指针
    []里的数据是一个地址值,这个地址指向一个双字型数据
    比如mov eax, dword ptr [12345678] 把内存地址12345678中的双字型(32位)数据赋给eax寄存器。

    • 2. 但是对于自定义类型,这就不一样了。

    2.1 a++与++a区别

    1. a++是先赋值再自增,++a是先自增再赋值。
    2. a++是先用临时对象保存原来的对象,然后对原对象自增,再返回临时对象,不能作为左值;++a是直接对于原对象进行自增,然后返回原对象的引用,可以作为左值。
    3. 由于要生成临时对象,a++需要调用两次拷贝构造函数与析构函数(将原对象赋给临时对象一次,临时对象以值传递方式返回一次);++a由于不用生成临时变量,且以引用方式返回,故没有构造与析构的开销,效率更高。

    左值一般是可以放在赋值符号左边的值,其在内存中有实体;右值一般只能放在赋值符号右边,不具有内存实体,无法通过取地址获得相应对象。

    考虑如下类:

    class Point{
        int x_;
        int y_;
    public:
        Point(int x = 0, int y = 0);
        Point(const Point&);
        ~Point();
        Point& operator++();//前置
        const Point operator++(int);//后置
        Point operator+(const Point&);
        Point& operator+=(const Point&);
        void DisplayPoint();
    };
    
    Point& Point::operator+=(const Point& _right)
    {
        this->x_ += _right.x_;
        this->y_ += _right.y_;
        return *this;
    }
    
    Point Point::operator+(const Point& _right)
    {
        Point temp;
        temp.x_ = this->x_ + _right.x_;
        temp.y_ = this->y_ + _right.y_;
        return temp;
    }
    
    
    Point& Point::operator++()
    {
        ++x_;
        ++y_;
        return *this;
    }
    
    const Point Point::operator++(int)
    {
        Point temp(*this);
        this->x_++;
        this->y_++;
        return temp;
    }
    
    Point::Point(int x, int y)
    {
        x_ = x;
        y_ = y;
        cout << "this is constructor" << endl;
    }
    
    Point::Point(const Point& b)
    {
        this->x_ = b.x_;
        this->y_ = b.y_;
        cout << "this is copy constructor" << endl;
    }
    
    Point::~Point()
    {
        cout << "this is destructor" << endl;
    }
    
    void Point::DisplayPoint()
    {
        cout << "x: " << this->x_ << endl;
        cout << "y: " << this->y_ << endl;
    }

    2.1.1 效率检测:

    Point a(1,1);
    cout << endl << "this is a++: " << endl;
    a++;
    cout << endl << "this is ++a: " << endl;
    ++a;

    将会输出:
    可以看到,a++将会有两次的拷贝构造与析构的调用,效率非常低。

    2.1.2 左右值检测:

    Point b(2, 2);
    Point* c;
    cout << endl << "this is &b: " << &b << endl;
    
    cout << endl << "this is c = &(++b): ";
    c = &(++b);
    cout << c << endl;
    
    cout << endl << "this is c = &(b++): ";
    c = &(b++);
    cout << c << endl;

    将会输出:
    可以看到++b返回的对象指针跟b原来的地址是一样的,而b++返回的对象地址跟原来的b地址不一样(应该是临时对象的地址),虽然可以取到地址,但当成左值将有可能导致错误。比如b++ = c;就不会将c给b,达不到原来的目的。为此,我们应该将后置的++函数返回值定义为const类型,就可以避免这种当成左值情况出现:const Point Point::operator++(int)。另外发现返回temp的引用可以减少一次拷贝和析构,但是不建议返回局部变量的引用!!因为函数退出,局部变量将析构,引用就会指向不确定内存。

    另外不要在一条语句中使用多个++,因为在不同系统中对这样的情况处理可能不一样,比如y = (4 + x++) + (6 + x++)。这条语句只能保证程序执行到下一条语句之前,x被递增两次,并不能保证4 + x++后立即自增。

    2.2 a+=b与a=a+b的区别

    a+=b返回的是a的引用,中间不涉及构造与析构,效率与++a一样。而a=a+b则会生成临时变量,而且以值传递方式返回,会有两次的构造与析构,与a++一样。

    参考

    i++和++i区别

    《C++ Primer Plus》第六版P133

  • 相关阅读:
    【BZOJ2288】生日礼物 [贪心]
    Tinyhttpd阅读笔记
    数据结构-图-经典算法(三)
    数据结构-图-经典算法(二)
    数据结构-图-经典算法(一)
    TCP协议的滑动窗口协议以及流量控制
    2016腾讯实习电话面试总结---2016-03-10
    B树,B+树,B*树
    平衡二叉树(AVL树)
    二叉搜索树(二叉查找树,二叉排序树)
  • 原文地址:https://www.cnblogs.com/HaoQChen/p/11048604.html
Copyright © 2011-2022 走看看