c++自古以來, 針對函式引數型別的傳遞一直都有一些約定俗成的規定, 比如:
針對原始資料型別,直接使用傳值形式傳參
void test(int number);void test(bool enable);void test(double percent);
而針對結構體以及類, 通常都是:
示例**
struct a ;class b ;void test_without_changed(const a& a);void test_without_changed(const b* b);void make_changed(a* a);void make_changed(b& b);a copy(const a& a);b copy(const b& b);
但是, 自動c++11之後這些或許就有一些變化了
在c++11開始, 引入了一個新的型別:右值引用
何為右值引用? 說通俗點就是出現在等號右邊的值的一個引用
與右值引用相對的肯定會有左值引用,即可以出現在等號左邊的值的引用
這倆傢伙具體有啥區別呢? 這裡我就不多講了, 自個兒查取咯
有了這個右值引用啊, c++11開始引入了一種新的拷貝:移動拷貝
什麼是移動拷貝呢?
移動拷貝就是在拷貝出一個新的物件時, 將舊物件的值(內部資源)直接移動到新物件,舊物件直接變為一個(資源全部轉移走了的)空物件
這又什麼好處呢?
你看啊, 假設我有一個物件, 管理著一塊相當大的記憶體,比如1g, 由於某種原因, 這個物件生命週期即將結束了, 但是該物件所管理的記憶體我還不想那麼早釋放掉, 我可以先使用移動構造將管理的記憶體塊轉移出去, 然後在其他地方繼續使用新的物件來管理這塊記憶體, 多好啊, 避免了資源釋放再重新申請的開銷
那再有了移動構造以後, 我們應該使用什麼形式的傳參更好呢?
需要拷貝 ——使用傳值
示例**
struct some ;/// 不拷貝,也不需要修改引數的值void test_without_copy_and_change(const some& some);void test_without_copy_and_change(const some* some);/// 不拷貝, 但是需要修改引數的值void change(some& some);void change(some* some);/// 拷貝some copy_and_change_some_options(some some); /// why ?
為什麼需要拷貝的時候 只需要用一中形式的傳參呢?
仔細想一想, 我們在引數傳值的時候會發生什麼 ? 當然會自動拷貝啊
對呀, 引數傳值, 自動拷貝呀, 多簡單
那為啥不寫成下面這種呢?
some copy_and_change_some_options(const some& some);
在c++11之前,確實這樣就可以了, 但是到了c++11之後, 上面的拷貝是不是還遺漏了什麼呢?
除了複製拷貝, 當然還得有個移動拷貝啊
那就是下面這樣咯:
some copy_and_change_some_options(const some& some);some copy_and_change_some_options(some&& some);
這多麻煩啊, 每多一種, 舊都要寫兩種, 像我這麼懶的人, 怎麼可能會每次都寫這麼多???
當然是直接寫成一種啊
some copy_and_change_some_options(some some);
為啥這一種就能處理上面兩種呢?
我們首先看複製構造
但我們直接傳遞一個物件做引數的時候, 是不是結果就跟複製拷貝一樣了, 同樣都是一次複製構造的開銷
some copy_and_change_some_options(const some& some)some copy_and_change_some_options(some some) /// 直接在傳值的時候一次copy
然後再看移動構造
傳值的時候, 的確都會呼叫一次建構函式, 但是並不是說, 傳值只會呼叫複製構造呀
我們傳值的時候, 把引數改成右值引用形式看看
some copy_and_change_some_options(some&& some)some copy_and_change_some_options(some some) /// 傳參時使用std::move(...) 一次move
果然開銷一樣
當不需要拷貝物件的時候, 我們使用引用或指標形式的引數, 如果不需要修改引數物件的值, 我們再加上const 修飾, 防止意外修改當需要拷貝引數物件的時候, 我們直接使用傳值形式的引數, 這樣既可以使用複製拷貝, 又可以使用移動拷貝, 很方便的合併了常量引用引數和右值引用引數