【c++11】C++11爲什麼需要std::ref/reference_wrapper

  • 看到一個用法
  • 容器裏是 std::reference_wrapper 對象
    std::vector<std::reference_wrapper<ParticipantObserver>> observers_;

  • 總結了下,可能以下三種情況需要用到:
  • vector裏不能直接存儲引用,又不想做拷貝
  • 丟入lamba或者函數是引用,
  • 如果設計意圖就是執行完畢後被對象會被修改

C++11爲什麼需要std::ref/reference_wrapper?

在std::promise範例中,使用了std::ref將future對象傳遞給引用參數類型的任務函數。

  • std::promise示例
  • 在這裏插入圖片描述
  • 如果直接傳入pr,將會出現編譯錯誤:
error C2661: “std::tuple,std::promise>::tuple”: 沒有重載函數接受 2 個參數
  • 說明函數調用的參數類型不匹配。

  • 查看thread的源代碼,其構造函數依賴於一個rvalue-reference類型的variaic templates參數列表:

template::type, thread>::value>::type>explicit
thread(_Fn&& _Fx, _Args&&... _Ax){
    // construct with _Fx(_Ax...)
    _Launch(&_Thr,
        _STD make_unique, decay_t<_Args>...> >(
            _STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...));
}
  • 其中的“_Args&&… _Ax”也是C++11引入的新特性:Variadic templates,

它允許函數可以接受任意個不同類型的參數,類似於C語言中的可變參數。
在參考文檔[4]中說,”However, thanks to variadic templates, programming new features using templates has become easier, clearer & more memory-efficient.“,
爲什麼內存效率更高呢?參考[6]中解釋說:參數列表所形成的一個parameter pack在編譯期間被解包,C++利用編譯期的處理實現了運行時效率優化。
參考[5]中說:”Variadic templates are a trustworthy solution to implement delegates and tuples. And, instead of C-style ellipsis mechanism, variadic templates can offer a typesafer solution to replace them.“具體如何實現delegates和tuples,另行描述。

  • 除了可變模板,另外兩個相關的新技術是rvalue-reference和reference_wrapper,這兩者和move語義是緊密相連的,如此節省了很多右值對象的複製構造開銷。

  • std::ref(pr)返回的對象類型是一個reference_wrapper,而不是對pr的直接引用(T&,即std::promise&)。

  • 換一個參考[7]中的例子:
    在這裏插入圖片描述

  • bind與reference_wrapper的示例第一部分

  • 上述代碼的結果是0!爲什麼?因爲bind方法通過傳值方式傳入參數,在被傳遞給綁定目標add方法之前,變量”result“已經被重新拷貝了。因爲bind必須確保傳入的參數是持續可用的。

  • 解決方法很簡單,使用reference_wrapper:
    在這裏插入圖片描述

  • bind與reference_wrapper的示例第二部分

  • 使用如下代碼定義reference_wrapper對象:

 reference_wrapper r=x;// or auto r = ref(x); 
  • 通過r對象的get函數(r.get()),r的作用與直接引用完全一樣。

引用數組的創建

  • 還可以用來創建引用數組,例如:
    在這裏插入圖片描述
  • std::reference_wrapper在泛型代碼中用處廣泛,它存儲的是對象的指針,有引用的全部功能,還實現了引用的拷貝(包括拷貝構造和拷貝賦值),可以在程序中存儲引用而不是整個對象。
  • reference_wrapper和shared_ptr如何選擇?兩者都可以實現指針層面的複製和操作,但是前者不允許默認構造函數,在容器中也不能使用resize等方法。另外可能還有一些不同之處,但是基本上沒有太大區別了。

參考資料:

[1] http://stackoverflow.com/questions/33240993/c-difference-between-stdreft-and-t
[2] http://stackoverflow.com/questions/26766939/difference-between-stdreference-wrapper-and-simple-pointer
[3] http://stackoverflow.com/questions/31013689/why-does-stdthread-take-function-to-run-by-rvalue
[4] http://softwareengineering.stackexchange.com/questions/273448/polymorphic-template-container-shared-ptr-vs-reference-wrapper
[5] http://www.cplusplus.com/articles/EhvU7k9E/
[6] Real-Time C++: Efficient Object-Oriented and Template Microcontroller Programming, 2015-12,Christopher Kormanyos
[7] https://oopscenities.net/2012/08/09/reference_wrapper/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章