1. 程式人生 > >++i、i++、i+=1、i=i+1的區別

++i、i++、i+=1、i=i+1的區別

面試被問到,上面這四個有什麼區別。

目錄

參考

  • 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++一樣。

參考

《C++ Primer Plus》第六版P133