1. 程式人生 > >關於std::move和std::forward

關於std::move和std::forward

這篇文章介紹的真不錯:http://www.cnblogs.com/catch/p/3507883.html

總結起來:

1. std::move是將左值變成右值減少不必要的拷貝;

2. std::forward保持一個值的左值和右值特性不變,以變傳給既能接受左值又能接受右值的函式,例:

template<class TYPE, class ARG>
TYPE* acquire_obj(ARG&& arg)
{
   return new TYPE(forward<ARG>(arg));
}

3. 本質上,std::move和std::forward底層實現都是呼叫static_cast來進行型別轉換的。所以在執行期間不會有任何額外的消耗。

4. 

在引數型別推導上,c++11 加入瞭如下兩個原則:

原則 (1):

引用摺疊原則 (reference collapsing rule),注意,以下條目中的 T 為具體型別,不是推導型別。

1)  T& & (引用的引用) 被轉化成 T&.

2)T&& & (rvalue的引用)被傳化成 T&.

3)  T& && (引用作rvalue) 被轉化成 T&.

4)  T&& && 被轉化成 T&&.

原則 (2):

對於以 rvalue reference 作為引數的模板函式,它的引數推導也有一個特殊的原則,假設函式原型為:

template<class TYPE, class ARG>
TYPE* acquire_obj(ARG&& arg);
1) 如果我們傳遞 lvalue 給 acquire_obj(),則 ARG 就會被推導為 ARG&,因此如下程式碼的第二行,acquire_obj 被推導為: TYPE* acquire_obj(ARG& &&)。

1 ARG arg;
2 acquire_obj(arg);
然後根據前面說的摺疊原則,我們得到原型如下的函式: TYPE* acquire_obj(ARG&);

2) 如果我們如下這樣傳遞 rvalue 給 acquire_obj(),則 ARG 就會被推導為 ARG。

acquire_obj(get_arg()); 
最後,模板函式例項化為原型如下的函式:TYPE* acquire_obj(ARG&&); 

綜上討論可見,原則 2 其實是有些令人討厭的,它與一般模板函式的引數型別推導並不一致,甚至可以說有些相背(主要在於 top level cv removal principle),這些隨處可見的例外增加了語言的複雜性,加大了學習和記憶的難度,是如此令人討厭,但在 c++ 中這種現象又那麼常見,真是無奈。