05 C 11 函式引數型別傳遞分析與總結

2022-06-23 21:03:59 字數 2728 閱讀 5045

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 修飾, 防止意外修改當需要拷貝引數物件的時候, 我們直接使用傳值形式的引數, 這樣既可以使用複製拷貝, 又可以使用移動拷貝, 很方便的合併了常量引用引數和右值引用引數