++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區別
- a++是先賦值再自增,++a是先自增再賦值。
- a++是先用臨時物件儲存原來的物件,然後對原物件自增,再返回臨時物件,不能作為左值;++a是直接對於原物件進行自增,然後返回原物件的引用,可以作為左值。
- 由於要生成臨時物件,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