最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解析C++11的std::ref、std::cref源碼

 更新時間:2021年05月11日 11:47:09   作者:彼方丶  
這篇文章主要介紹了解析C++11的std::ref、std::cref源碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1、源碼準備

本文是基于gcc-4.9.0的源代碼進行分析,std::ref和std::cref是C++11才加入標準的,所以低版本的gcc源碼是沒有這兩個的,建議選擇4.9.0或更新的版本去學(xué)習(xí),不同版本的gcc源碼差異應(yīng)該不小,但是原理和設(shè)計思想的一樣的,下面給出源碼下載地址
http://ftp.gnu.org/gnu/gcc

2、std::ref和std::cref的作用

C++本身就有引用(&),那為什么C++11又引入了std::ref(或者std::cref)呢?
主要是考慮函數(shù)式編程(如std::bind)在使用時,是對參數(shù)直接拷貝,而不是引用。下面是一個簡單的例子:

#include <functional>
#include <iostream>
void fun(int& n1, int& n2, const int& n3)
{
    std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
    ++n1; // increments the copy of n1 stored in the function object
    ++n2; // increments the main()'s n2
    // ++n3; // compile error
    std::cout << "In function end: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
}
 
int main()
{
    int n1 = 1, n2 = 1, n3 = 1;
    std::function<void()> fff = std::bind(f, n1, std::ref(n2), std::cref(n3));
    std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
    fff();
    std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
}

運行結(jié)果:

Before function: 1 1 1
In function: 1 1 1
In function end: 2 2 1
After function: 1 2 1

從上面的例子中可以看到,執(zhí)行完fff,n1的值仍然是1,n2的值已經(jīng)改變,這說明std::bind使用的是參數(shù)的拷貝而不是引用,這也就是為什么C++11要引入std::ref和std::cref的原因了,接下來分析std::ref的實現(xiàn)(std::cref不作分析,因為和std::ref的位移差別只是引用變成了const而已)

3、std::ref相關(guān)源碼解析

3.1、std::ref解析

std::ref位于libstdc++-v3\include\std\functional中

template<typename _Tp>
inline reference_wrapper<_Tp> ref(_Tp& __t) noexcept
{ return reference_wrapper<_Tp>(__t); }

template<typename _Tp>
void ref(const _Tp&&) = delete;

template<typename _Tp>
inline reference_wrapper<_Tp> ref(reference_wrapper<_Tp> __t) noexcept
{ return ref(__t.get()); }

從源代碼中可以看出:

  • std::ref是一個模板函數(shù),返回值是模板類std::reference_wrapper
  • 從第二個函數(shù)可以看到,std::ref不允許傳遞右值引用參數(shù),即無法包裝右值引用傳遞的值
  • std::ref的傳入?yún)?shù)可以是一個普通的引用,也可以是另外一個std::reference_wrapper對象,接下來分析std::reference_wrapper的實現(xiàn)

3.2、std::reference_wrapper解析

std::reference_wrapper位于libstdc++-v3\include\std\functional中

template<typename _Tp>
class reference_wrapper : public _Reference_wrapper_base<typename remove_cv<_Tp>::type>
{
    _Tp* _M_data;

public:
    typedef _Tp type;

    reference_wrapper(_Tp& __indata) noexcept
        :_M_data(std::__addressof(__indata))
    {
    }

    reference_wrapper(_Tp&&) = delete;

    reference_wrapper(const reference_wrapper<_Tp>& __inref) noexcept
        :_M_data(__inref._M_data)
    {
    }

    reference_wrapper& operator=(const reference_wrapper<_Tp>& __inref) noexcept
    {
        _M_data = __inref._M_data;
        return *this;
    }

    operator _Tp&() const noexcept
    { return this->get(); }

    _Tp& get() const noexcept
    { return *_M_data; }

    template<typename... _Args>
    typename result_of<_Tp&(_Args&&...)>::type
    operator()(_Args&&... __args) const
    {
        return __invoke(get(), std::forward<_Args>(__args)...);
    }
};

從源代碼中可以獲得以下信息:

  • 該類繼承于std::_Reference_wrapper_base
  • 有一個類成員_M_data,類型為所引用類型的指針
  • 第一個構(gòu)造函數(shù)通過調(diào)用std::__addressof函數(shù),獲得了指向引用參數(shù)的指針,并賦值給了_M_data(這也是為什么不支持右值引用的原因,因為取不到對應(yīng)的地址),std::__addressof實現(xiàn)如下:
// 位于**libstdc++-v3\include\bits\move.h**中
// 借助reinterpret_cast能任意轉(zhuǎn)換類型的特性來將<code>_Tp&</code>轉(zhuǎn)為<code>_Tp*</code>
//(轉(zhuǎn)換過程編譯器不保證正確,要由程序員來保證轉(zhuǎn)換過程不出錯,雖然標準庫用了很多這樣的特殊技巧,但是實際開發(fā)中這些少用為好)
template<typename _Tp>
inline _Tp* __addressof(_Tp& __r) _GLIBCXX_NOEXCEPT
{
    return reinterpret_cast<_Tp*>(&const_cast<char&>(reinterpret_cast<const volatile char&>(__r)));
}
  • 拷貝構(gòu)造函數(shù)和賦值函數(shù)就只是簡單地將_M_data的值進行傳遞而已了
  • 其余方法就是為了讓std::reference_wrapper展現(xiàn)出和普通的引用一樣的效果而進行的運算符重載啥的,這里就不贅述了,實現(xiàn)比較簡單,大家可以自己看一看具體的代碼

3.3、std::remove_cv解析

std::remove_cv位于libstdc+±v3\include\std\type_traits中

分析std::_Reference_wrapper_base之前先看一下std::remove_cv的實現(xiàn)
其實從std::remove_cv存在于type_traits文件這一點就可以大致推斷出,std::remove_cv使用了模板元技術(shù),模板元的主要思想為:利用模板特化機制實現(xiàn)編譯期條件選擇結(jié)構(gòu),利用遞歸模板實現(xiàn)編譯期循環(huán)結(jié)構(gòu),模板元程序則由編譯器在編譯器解釋運行,但是其也有明顯的優(yōu)缺點,優(yōu)點是運行時速度極快,缺點是程序很難看懂,容易勸退初學(xué)者,這里不對其做深入分析,知道是這樣一個東西就行,有興趣的可以去查閱專業(yè)的C++書籍去了解其中的奧秘
源代碼如下,作用是將模板_Tp的const和voaltile屬性分離,這樣的話使用::value就可以得到?jīng)]有const、volatile的類型了

/// remove_const
template<typename _Tp>
struct remove_const
{ typedef _Tp    type; };

template<typename _Tp>
struct remove_const<_Tp const>
{ typedef _Tp    type; };

/// remove_volatile
template<typename _Tp>
struct remove_volatile
{ typedef _Tp    type; };

template<typename _Tp>
struct remove_volatile<_Tp volatile>
{ typedef _Tp    type; };

/// remove_cv
template<typename _Tp>
struct remove_cv
{
  typedef typename
  remove_const<typename remove_volatile<_Tp>::type>::type    type;
};

3.4、std::_Reference_wrapper_base解析

std::_Reference_wrapper_base位于libstdc++-v3\include\std\functional中

template<typename _Tp>
struct _Reference_wrapper_base
    :_Reference_wrapper_base_impl<
     __has_argument_type<_Tp>::value,
     __has_first_argument_type<_Tp>::value
     && __has_second_argument_type<_Tp>::value,
     _Tp>
{};

template<typename _Res, typename _T1>
struct _Reference_wrapper_base<_Res(_T1)> : unary_function<_T1, _Res>
{};

template<typename _Res, typename _T1>
struct _Reference_wrapper_base<_Res(_T1) const> : unary_function<_T1, _Res>
{};

template<typename _Res, typename _T1>
struct _Reference_wrapper_base<_Res(_T1) volatile> : unary_function<_T1, _Res>
{};

template<typename _Res, typename _T1>
struct _Reference_wrapper_base<_Res(_T1) const volatile> : unary_function<_T1, _Res>
{};

// - a function type (binary)
template<typename _Res, typename _T1, typename _T2>
struct _Reference_wrapper_base<_Res(_T1, _T2)> : binary_function<_T1, _T2, _Res>
{};

template<typename _Res, typename _T1, typename _T2>
struct _Reference_wrapper_base<_Res(_T1, _T2) const> : binary_function<_T1, _T2, _Res>
{};

template<typename _Res, typename _T1, typename _T2>
struct _Reference_wrapper_base<_Res(_T1, _T2) volatile> : binary_function<_T1, _T2, _Res>
{};

template<typename _Res, typename _T1, typename _T2>
struct _Reference_wrapper_base<_Res(_T1, _T2) const volatile> : binary_function<_T1, _T2, _Res>
{};

template<typename _Res, typename _T1>
struct _Reference_wrapper_base<_Res(*)(_T1)> : unary_function<_T1, _Res>
{};

template<typename _Res, typename _T1, typename _T2>
struct _Reference_wrapper_base<_Res(*)(_T1, _T2)> : binary_function<_T1, _T2, _Res>
{};

template<typename _Res, typename _T1>
struct _Reference_wrapper_base<_Res (_T1::*)()> : unary_function<_T1*, _Res>
{};

template<typename _Res, typename _T1, typename _T2>
struct _Reference_wrapper_base<_Res (_T1::*)(_T2)> : binary_function<_T1*, _T2, _Res>
{};

template<typename _Res, typename _T1>
struct _Reference_wrapper_base<_Res (_T1::*)() const> : unary_function<const _T1*, _Res>
{};

template<typename _Res, typename _T1, typename _T2>
struct _Reference_wrapper_base<_Res (_T1::*)(_T2) const> : binary_function<const _T1*, _T2, _Res>
{};

template<typename _Res, typename _T1>
struct _Reference_wrapper_base<_Res (_T1::*)() volatile> : unary_function<volatile _T1*, _Res>
{};

template<typename _Res, typename _T1, typename _T2>
struct _Reference_wrapper_base<_Res (_T1::*)(_T2) volatile> : binary_function<volatile _T1*, _T2, _Res>
{};

template<typename _Res, typename _T1>
struct _Reference_wrapper_base<_Res (_T1::*)() const volatile> : unary_function<const volatile _T1*, _Res>
{};

template<typename _Res, typename _T1, typename _T2>
struct _Reference_wrapper_base<_Res (_T1::*)(_T2) const volatile> : binary_function<const volatile _T1*, _T2, _Res>
{};

從代碼中可以看出,std::_Reference_wrapper_base繼承于std::unary_function或者std::binary_function,在實際編程中對std::reference_wrapper的作用不大,除非引用的是一個函數(shù)對象,所以在這里就不分析它的具體作用了,大家直接去查一下unary_function和binary_function是啥東西就行了

4、總結(jié)

std::ref和std::cref在函數(shù)式編程中的作用是非常大的,C++11后的源代碼中多次使用到了它們。而std::ref和std::cref事實上是模板函數(shù),返回值是一個std::reference_wrapper對象,而std::reference_wrapper雖然是一個對象,可是他卻能展現(xiàn)出和普通引用類似的效果,這點和前一篇文章講的智能指針如出一轍(事實上標準庫大多是這樣設(shè)計的,這也是運算符重載存在的一個重要意義)。當我們在函數(shù)式編程(如std::bind)中需要對參數(shù)進行引用傳遞時,只需要用std::ref或std::cref修飾該引用即可

到此這篇關(guān)于解析C++11的std::ref、std::cref源碼的文章就介紹到這了,更多相關(guān)C++11 std::ref、std::cref 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++實現(xiàn)圖書管理系統(tǒng)(文件操作與類)

    C++實現(xiàn)圖書管理系統(tǒng)(文件操作與類)

    這篇文章主要為大家詳細介紹了C++實現(xiàn)圖書管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 從匯編看c++中引用與指針的使用分析

    從匯編看c++中引用與指針的使用分析

    在c++中,引用和指針具有相同的作用,都可以用來在函數(shù)里面給變函數(shù)外面對象或者變量的值,下面就來看他們的原理
    2013-05-05
  • C語言實現(xiàn)簡易掃雷游戲詳解

    C語言實現(xiàn)簡易掃雷游戲詳解

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)簡易掃雷游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Qt中QZXing 的編譯與使用

    Qt中QZXing 的編譯與使用

    本文主要介紹了Qt中QZXing 的編譯與使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++?11新特性之右值引用使用案例與應(yīng)用場景

    C++?11新特性之右值引用使用案例與應(yīng)用場景

    右值引用和move語義是C++ 11中重要的特性之一,可以提高程序的效率和性能,右值引用是一種新的引用類型,下面這篇文章主要給大家介紹了關(guān)于C++?11新特性之右值引用使用案例與應(yīng)用場景的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • Qt QDir路徑類及使用方法

    Qt QDir路徑類及使用方法

    QDir是Qt中用于操作文件系統(tǒng)目錄的類,提供了多種方法來管理和查詢目錄,如設(shè)置當前目錄、列舉文件和子目錄、創(chuàng)建和刪除目錄等,它支持基于字符串路徑的操作,并且可以使用過濾器和排序功能,通過示例代碼,展示了如何使用QDir進行各種目錄操作,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • C++使struct對象擁有可變大小的數(shù)組(詳解)

    C++使struct對象擁有可變大小的數(shù)組(詳解)

    下面小編就為大家?guī)硪黄狢++使struct對象擁有可變大小的數(shù)組(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • C++類繼承之子類調(diào)用父類的構(gòu)造函數(shù)的實例詳解

    C++類繼承之子類調(diào)用父類的構(gòu)造函數(shù)的實例詳解

    這篇文章主要介紹了C++類繼承之子類調(diào)用父類的構(gòu)造函數(shù)的實例詳解的相關(guān)資料,希望通過本文大家能夠掌握C++類繼承的相關(guān)知識,需要的朋友可以參考下
    2017-09-09
  • C語言字符串函數(shù),字符函數(shù),內(nèi)存函數(shù)使用及模擬實現(xiàn)

    C語言字符串函數(shù),字符函數(shù),內(nèi)存函數(shù)使用及模擬實現(xiàn)

    這篇文章主要介紹了C語言字符串函數(shù),字符函數(shù),內(nèi)存函數(shù)使用及模擬實現(xiàn),文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • C語言實現(xiàn)哈夫曼樹的構(gòu)建

    C語言實現(xiàn)哈夫曼樹的構(gòu)建

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)哈夫曼樹的構(gòu)建,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04

最新評論

唐河县| 昌都县| 石棉县| 诏安县| 台前县| 温泉县| 襄汾县| 罗田县| 通河县| 北安市| 清丰县| 平和县| 南涧| 芮城县| 绥宁县| 田阳县| 凤山县| 登封市| 淮安市| 延吉市| 蓝山县| 饶平县| 新乡市| 探索| 麦盖提县| 怀来县| 民丰县| 邵阳县| 景东| 会同县| 永仁县| 商城县| 原平市| 江西省| 天祝| 上蔡县| 江孜县| 盱眙县| 桂林市| 镇原县| 泰兴市|