0. 寫在最前面
希望大家收藏:
本文持續更新地址:https://haoqchen.site/2018/10/15/difference-between-++i-i++-i+=1-i=i+1/
面試被問到,上面這四個有什麼區別。總結了一下,如果覺得還不錯就點個贊,點個關注唄,博主會長期更新自己的學習和收穫。
目錄
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