淺談C++11的std::function源碼解析

1、源碼準備

本文是基於gcc-4.9.0的源代碼進行分析,std::function是C++11才加入標準的,所以低版本的gcc源碼是沒有std::function的,建議選擇4.9.0或更新的版本去學習,不同版本的gcc源碼差異應該不小,但是原理和設計思想的一樣的。
源碼下載地址:http://ftp.gnu.org/gnu/gcc

2、std::function簡介

類模版std::function是一種通用的多態函數包裝器。std::function的實例可以對任何可以調用的目標實體進行存儲、復制、和調用操作,這些目標實體包括普通函數指針、類成員函數指針(第一個參數需要傳入對應的this指針)、Lambda表達式或者某個類的實例(前提是這個類重載瞭()運算符)。std::function對象是對C++中現有的可調用實體的一種類型安全的包裹(我們知道像函數指針這類可調用實體,是類型不安全的)。

通常std::function是一個函數對象類,它包裝其它任意的可調用實體,被包裝的對象具有類型為T1,…,TN的N個參數,並且返回一個可轉換到R類型的值。std::function使用模板轉換構造函數接收被包裝的函數對象;特別是,閉包類型可以隱式地轉換為std::function。最簡單的理解就是通過std::function對C++中各種可調用實體的封裝,形成一個新的可調用的std::function對象,讓我們不再糾結那麼多的可調用實體之間如何進行方便高效的轉換。

3、源碼解析

3.1、std::function解析

std::function位於libstdc++-v3\include\std\functional中

template<typename _Res, typename... _ArgTypes>
class function<_Res(_ArgTypes...)> : public _Maybe_unary_or_binary_function<_Res, _ArgTypes...>, private _Function_base
{
    typedef _Res _Signature_type(_ArgTypes...);

    template<typename _Functor>
    using _Invoke = decltype(__callable_functor(std::declval<_Functor&>())(std::declval<_ArgTypes>()...) );

    template<typename _Functor>
    using _Callable = __check_func_return_type<_Invoke<_Functor>, _Res>;

    template<typename _Cond, typename _Tp>
    using _Requires = typename enable_if<_Cond::value, _Tp>::type;

public:
    typedef _Res result_type;

    function() noexcept
        :_Function_base()
    {
    }

    function(nullptr_t) noexcept
        :_Function_base()
    {
    }

    template<typename _Res, typename... _ArgTypes>
    function(const function& __x)
        :_Function_base()
    {
        if (static_cast<bool>(__x))
        {
            _M_invoker = __x._M_invoker;
            _M_manager = __x._M_manager;
            __x._M_manager(_M_functor, __x._M_functor, __clone_functor);
        }
    }

    function(function&& __x)
        :_Function_base()
    { __x.swap(*this); }

    template<typename _Functor, typename = _Requires<_Callable<_Functor>, void>>
    function(_Functor __f)
    {
        typedef _Function_handler<_Signature_type, _Functor> _My_handler;

        if (_My_handler::_M_not_empty_function(__f))
        {
            _My_handler::_M_init_functor(_M_functor, std::move(__f));
            _M_invoker = &_My_handler::_M_invoke;
            _M_manager = &_My_handler::_M_manager;
        }
    }

    function& operator=(const function& __x)
    {
        function(__x).swap(*this);
        return *this;
    }

    function& operator=(function&& __x)
    {
        function(std::move(__x)).swap(*this);
        return *this;
    }

    function& operator=(nullptr_t)
    {
        if (_M_manager)
        {
            _M_manager(_M_functor, _M_functor, __destroy_functor);
            _M_manager = 0;
            _M_invoker = 0;
        }
        return *this;
    }

    template<typename _Functor>
    _Requires<_Callable<_Functor>, function&> operator=(_Functor&& __f)
    {
        function(std::forward<_Functor>(__f)).swap(*this);
        return *this;
    }

    template<typename _Functor>
    function& operator=(reference_wrapper<_Functor> __f) noexcept
    {
        function(__f).swap(*this);
        return *this;
    }

    void swap(function& __x)
    {
        std::swap(_M_functor, __x._M_functor);
        std::swap(_M_manager, __x._M_manager);
        std::swap(_M_invoker, __x._M_invoker);
    }

     explicit operator bool() const noexcept
     { return !_M_empty(); }

    _Res operator()(_ArgTypes... __args) const;
    {
        if (_M_empty())
            __throw_bad_function_call();
        return _M_invoker(_M_functor, std::forward<_ArgTypes>(__args)...);
    }

private:
    typedef _Res (*_Invoker_type)(const _Any_data&, _ArgTypes...);
    _Invoker_type _M_invoker;

從源代碼中可以看出以下幾點信息:

  • 該類是一個可變參模板類
  • 該類繼承於_Maybe_unary_or_binary_function(不分析)和_Function_base,類成員隻有_M_invoker一個,從定義可以看出這是一個標準的函數指針
  • 首先分析operator()方法,平時開發中std::function使用最多的肯定就是重載的括號運算符瞭,畢竟最終也是要把它當成類似於函數的形式來調用的。可以看到operator()函數裡面調用瞭_M_invoker函數,並沒有什麼特殊的處理
  • 既然_M_invoker能被調用,那就說明它肯定被初始化過瞭,從調用時傳給他的參數來看,多瞭一個不知道是什麼的參數_M_functor,所以我們可以猜測_M_invoker並不是直接指向std::function接管的可調用實體的,而是一個類似中間層的東西,在_M_invoker的實現裡面才調用瞭我們需要執行的那個真實的可調用實體
  • 隻有構造函數function(_Functor __f)對_M_invoker進行瞭初始化,而使用的就是std::_Function_handler裡的方法來初始化_M_invoker的,std::_Function_handler的實現在後面會講到
  • 還是看構造函數function(_Functor __f),因為std::function的目的就是對我們傳入的可調用實體進行包裝,這裡說的可調用實體可以是普通函數指針、類成員函數指針(第一個參數需要傳入對應的this指針)、Lambda表達式以及某個類實例(前提是這個類重載瞭()運算符),而我們看到在std::function這個類裡面並沒有直接托管我們傳入的可調用實體,而隻是調用瞭_My_handler::_M_init_functor(_M_functor, std::move(__f)),推測是由_Function_base來托管可調用實體的

3.2、std::_Function_handler解析

std::_Function_handler位於libstdc++-v3\include\std\functional中

template<typename _Res, typename _Functor, typename... _ArgTypes>
class _Function_handler<_Res(_ArgTypes...), _Functor> : public _Function_base::_Base_manager<_Functor>
{
    typedef _Function_base::_Base_manager<_Functor> _Base;

public:
    static _Res _M_invoke(const _Any_data& __functor, _ArgTypes... __args)
    {
        return (*_Base::_M_get_pointer(__functor))(std::forward<_ArgTypes>(__args)...);
    }
};

template<typename _Functor, typename... _ArgTypes>
class _Function_handler<void(_ArgTypes...), _Functor> : public _Function_base::_Base_manager<_Functor>
{
    typedef _Function_base::_Base_manager<_Functor> _Base;

public:
    static void _M_invoke(const _Any_data& __functor, _ArgTypes... __args)
    {
        (*_Base::_M_get_pointer(__functor))(std::forward<_ArgTypes>(__args)...);
    }
};

template<typename _Res, typename _Functor, typename... _ArgTypes>
class _Function_handler<_Res(_ArgTypes...), reference_wrapper<_Functor> > : public _Function_base::_Ref_manager<_Functor>
{
    typedef _Function_base::_Ref_manager<_Functor> _Base;

public:
    static _Res _M_invoke(const _Any_data& __functor, _ArgTypes... __args)
    {
        return __callable_functor(**_Base::_M_get_pointer(__functor))(std::forward<_ArgTypes>(__args)...);
    }
};

template<typename _Functor, typename... _ArgTypes>
class _Function_handler<void(_ArgTypes...), reference_wrapper<_Functor> > : public _Function_base::_Ref_manager<_Functor>
{
    typedef _Function_base::_Ref_manager<_Functor> _Base;

public:
    static void _M_invoke(const _Any_data& __functor, _ArgTypes... __args)
    {
        __callable_functor(**_Base::_M_get_pointer(__functor))(std::forward<_ArgTypes>(__args)...);
    }
};

template<typename _Class, typename _Member, typename _Res, typename... _ArgTypes>
class _Function_handler<_Res(_ArgTypes...), _Member _Class::*> : public _Function_handler<void(_ArgTypes...), _Member _Class::*>
{
    typedef _Function_handler<void(_ArgTypes...), _Member _Class::*> _Base;

public:
    static _Res _M_invoke(const _Any_data& __functor, _ArgTypes... __args)
    {
        return std::mem_fn(_Base::_M_get_pointer(__functor)->__value)(std::forward<_ArgTypes>(__args)...);
    }
};

template<typename _Class, typename _Member, typename... _ArgTypes>
class _Function_handler<void(_ArgTypes...), _Member _Class::*> : public _Function_base::_Base_manager<_Simple_type_wrapper< _Member _Class::* > >
{
    typedef _Member _Class::* _Functor;
    typedef _Simple_type_wrapper<_Functor> _Wrapper;
    typedef _Function_base::_Base_manager<_Wrapper> _Base;

public:
    static bool _M_manager(_Any_data& __dest, const _Any_data& __source, _Manager_operation __op)
    {
        switch (__op)
        {
            #ifdef __GXX_RTTI
            case __get_type_info:
                __dest._M_access<const type_info*>() = &typeid(_Functor);
                break;
            #endif

            case __get_functor_ptr:
                __dest._M_access<_Functor*>() = &_Base::_M_get_pointer(__source)->__value;
                break;

            default:
                _Base::_M_manager(__dest, __source, __op);
        }
        return false;
    }

    static void _M_invoke(const _Any_data& __functor, _ArgTypes... __args)
    {
        std::mem_fn(_Base::_M_get_pointer(__functor)->__value)(std::forward<_ArgTypes>(__args)...);
    }
};

從源代碼中可以看出_Function_handler有六種重載形式,以下對其進行分類說明:

  • 第一個和第二個重載形式繼承於std::_Function_base::_Base_manager,當std::function接管的可調用實體是一個普通函數指針、類實例或者Lambda表達式時,發揮作用的就是這兩個類。裡面的內容很簡單,通過調用_Function_base::_Base_manager<_Functor>的_M_get_pointer方法從__functor中取出對應的可調用實體,然後直接執行,我們知道能直接執行的可調用實體的類型是普通函數指針、類實例(必須重載瞭()運算符)或者Lambda表達式(Lambda其實本質就是一個匿名的類實例)。這兩個重載形式的唯一區別就是它們一個處理函數有返回值的情況,另一個處理沒返回值的情況。
  • 第三個和第四個重載形式繼承於std::_Function_base::_Ref_manager,可以看出它們基本上算是前兩個類的偏特化版本,當第二個模板參數為std::reference_wrapper包裝的引用時,就調用這兩個偏特化的版本。這兩個重載形式的唯一區別也是它們一個處理函數有返回值的情況,另一個處理沒返回值的情況。現在問題來瞭,為什麼要搞一個對於std::reference_wrapper類型的偏特化版本呢?這是因為如果可調用實體已經先被std::reference_wrapper包裝過的話,那我們是絕對絕對不能直接調用這個可調用實體的,因為此時根本不確定這個被包裝的可調用實體究竟是什麼類型的,如果是類成員函數的話那當然是不能直接調用的,此時必須使用std::mem_fn來獲取一個可調用的對象,類中使用的std::__callable_functor函數的實現如下面的代碼所示,可以看到有好幾種特化版本,當std::reference_wrapper包裝的可調用實體是一個類成員函數指針時,就會通過std::mem_fn來獲取一個可調用的對象,這和前面描述的內容一致。
template<typename _Functor>
inline _Functor& __callable_functor(_Functor& __f)
{ return __f; }

template<typename _Member, typename _Class>
inline _Mem_fn<_Member _Class::*> __callable_functor(_Member _Class::* &__p)
{ return std::mem_fn(__p); }

template<typename _Member, typename _Class>
inline _Mem_fn<_Member _Class::*> __callable_functor(_Member _Class::* const &__p)
{ return std::mem_fn(__p); }

template<typename _Member, typename _Class>
inline _Mem_fn<_Member _Class::*> __callable_functor(_Member _Class::* volatile &__p)
{ return std::mem_fn(__p); }

template<typename _Member, typename _Class>
inline _Mem_fn<_Member _Class::*> __callable_functor(_Member _Class::* const volatile &__p)
{ return std::mem_fn(__p); }

關於上面提到的std::reference_wrapper和std::mem_fn,大傢如果可以不懂的話一定要看下面兩篇文章,不然的話就像學英語不會英語單詞一樣,根本不可能看懂std::function的內容的

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

  • 第五個和第六個重載形式和前面的差不多,這兩個也是屬於偏特化版本,主要是用於處理可調用實體為類成員函數指針的情況,這裡就可以看到直接調用瞭std::men_fn函數來使得我們可以直接調用對應的類成員函數,從這點也可以看出std::men_fn函數的重要性,不懂的小夥伴一定要去看前面兩篇文章啊。
  • 每一個類裡面的_M_invoke函數都用瞭_M_get_pointer(來源不全部相同),從代碼邏輯上不難看出_M_get_pointer函數的作用是從第一個傳入參數__functor中取出對應的可調用實體,然後將後面的可變參傳給這個可調用實體,運行它,這個功能是不是就有點似曾相識瞭?對,這就是我們平時正常調用函數的那樣子嘛,也就是說std::function的函數執行功能在這裡實現瞭
  • 從代碼中我們可以看出這幾個類都是和std::_Function_base相關的,並且到現在還是不知道_M_functor究竟是個什麼東西,接下來分析std::_Function_base,看一下裡面究竟做瞭哪些工作

3.3、_Any_data解析

_Any_data位於libstdc++-v3\include\std\functional中

union _Nocopy_types
{
    void*       _M_object;
    const void* _M_const_object;
    void (*_M_function_pointer)();
    void (_Undefined_class::*_M_member_pointer)();
};

union _Any_data
{
    void*       _M_access()       { return &_M_pod_data[0]; }
    const void* _M_access() const { return &_M_pod_data[0]; }

    template<typename _Tp>
    _Tp& _M_access()
    { return *static_cast<_Tp*>(_M_access()); }

    template<typename _Tp>
    const _Tp& _M_access() const
    { return *static_cast<const _Tp*>(_M_access()); }

    _Nocopy_types _M_unused;
    char _M_pod_data[sizeof(_Nocopy_types)];
};

看std::_Function_base之前先看一個重要的聯合體_Any_data,這個在前面出現很多次瞭,但是一直沒有介紹一下它究竟是個什麼東西,下面簡單分析一下:

  • 有兩個聯合體成員,一個是_M_unused(沒卵用),一個是_M_pod_data,這兩個的占用內存是一樣的,具體原因就不講瞭,大傢可以自己用sizeof去試一下
  • 裡面有四個_M_access函數,前兩個是直接將_M_pod_data的地址返回出去,不做任何轉換,後兩個則是可以將_M_pod_data轉換為任意類型返回,從這裡可以看出這個_Any_data的作用就是來接管可調用對象的,所以後續可以通過各種轉換將它還原為可調用的形式(比如前面提到的那個_Function_base::_Base_manager<_Functor>::_M_get_pointer方法就是幹這個貨活的)
  • 簡單看一下_Nocopy_types這個聯合體,前兩個成員的寓意就是類實例或Lambda表達式,第三個寓意是普通函數指針,第四個寓意是類成員函數指針,仔細一看這不就是我們前面提到無數次的可調用實體的幾種形式嗎?這個_Nocopy_types從上下文看來並沒有什麼亂用,估計就是源碼作者寫給讀者看的吧,讓大傢更容易讀懂源碼。

3.4、std::_Function_base解析

std::_Function_base的實現位於libstdc++-v3\include\std\functional中

class _Function_base
{
public:
    static const std::size_t _M_max_size = sizeof(_Nocopy_types);
    static const std::size_t _M_max_align = __alignof__(_Nocopy_types);

    template<typename _Functor>
    class _Base_manager
    {
    protected:
        static const bool __stored_locally =
            (__is_location_invariant<_Functor>::value
            && sizeof(_Functor) <= _M_max_size
            && __alignof__(_Functor) <= _M_max_align
            && (_M_max_align % __alignof__(_Functor) == 0));

        typedef integral_constant<bool, __stored_locally> _Local_storage;

        static _Functor* _M_get_pointer(const _Any_data& __source)
        {
            const _Functor* __ptr = __stored_locally? std::__addressof(__source._M_access<_Functor>()) : __source._M_access<_Functor*>();
            return const_cast<_Functor*>(__ptr);
        }

        static void _M_clone(_Any_data& __dest, const _Any_data& __source, true_type)
        {
            new (__dest._M_access()) _Functor(__source._M_access<_Functor>());
        }

        static void _M_clone(_Any_data& __dest, const _Any_data& __source, false_type)
        {
            __dest._M_access<_Functor*>() = new _Functor(*__source._M_access<_Functor*>());
        }

        static void _M_destroy(_Any_data& __victim, true_type)
        {
            __victim._M_access<_Functor>().~_Functor();
        }

        static void _M_destroy(_Any_data& __victim, false_type)
        {
            delete __victim._M_access<_Functor*>();
        }

    public:
        static bool _M_manager(_Any_data& __dest, const _Any_data& __source, _Manager_operation __op)
        {
            switch (__op)
            {
                case __get_functor_ptr:
                    __dest._M_access<_Functor*>() = _M_get_pointer(__source);
                    break;

                case __clone_functor:
                    _M_clone(__dest, __source, _Local_storage());
                    break;

                case __destroy_functor:
                    _M_destroy(__dest, _Local_storage());
                    break;
            }
            return false;
        }

        static void _M_init_functor(_Any_data& __functor, _Functor&& __f)
        { _M_init_functor(__functor, std::move(__f), _Local_storage()); }

        template<typename _Signature>
        static bool _M_not_empty_function(const function<_Signature>& __f)
        { return static_cast<bool>(__f); }

        template<typename _Tp>
        static bool _M_not_empty_function(_Tp* const& __fp)
        { return __fp; }

        template<typename _Class, typename _Tp>
        static bool _M_not_empty_function(_Tp _Class::* const& __mp)
        { return __mp; }

        template<typename _Tp>
        static bool _M_not_empty_function(const _Tp&)
        { return true; }

    private:
        static void _M_init_functor(_Any_data& __functor, _Functor&& __f, true_type)
        { new (__functor._M_access()) _Functor(std::move(__f)); }

        static void _M_init_functor(_Any_data& __functor, _Functor&& __f, false_type)
        { __functor._M_access<_Functor*>() = new _Functor(std::move(__f)); }
    };

    template<typename _Functor>
    class _Ref_manager : public _Base_manager<_Functor*>
    {
        typedef _Function_base::_Base_manager<_Functor*> _Base;

    public:
        static bool _M_manager(_Any_data& __dest, const _Any_data& __source, _Manager_operation __op)
        {
            switch (__op)
            {
                case __get_functor_ptr:
                    __dest._M_access<_Functor*>() = *_Base::_M_get_pointer(__source);
                    return is_const<_Functor>::value;
                    break;

                default:
                    _Base::_M_manager(__dest, __source, __op);
            }
            return false;
        }

        static void _M_init_functor(_Any_data& __functor, reference_wrapper<_Functor> __f)
        {
            _Base::_M_init_functor(__functor, std::__addressof(__f.get()));
        }
    };

    _Function_base() : _M_manager(0) { }

    ~_Function_base()
    {
        if (_M_manager)
            _M_manager(_M_functor, _M_functor, __destroy_functor);
    }

    bool _M_empty() const { return !_M_manager; }

    typedef bool (*_Manager_type)(_Any_data&, const _Any_data&, _Manager_operation);

    _Any_data     _M_functor;
    _Manager_type _M_manager;
};

從源代碼中可以看出以下幾點信息:

  • 該類有兩個類成員,分別是_M_functor和_M_manager,_M_functor就不用多說瞭,前面一直有提到它,他的類型_Any_data也在上一小節講過瞭。而_M_manager則是一個函數指針,下面再介紹它有什麼用。
  • 這裡看一下_Function_base::_Base_manager類裡面的各個方法
    • _M_init_functor函數:該函數前面提到過瞭,當時看到的是將std::function接管的可調用對象傳遞給瞭這個函數,而從前面我們知道_Any_data類型的數據是可以接管所有形式的可調用實體的,所以綜合可得_M_init_functor函數的作用就是將傳遞給它的第二個參數儲存到第一個參數中(_Any_data類型數據),這樣就達成瞭接管可調用實體的功能瞭
    • _M_get_pointer函數:這個函數同樣在前面提到過,當時我們隻知道通過調用_M_get_pointer可以獲取到我們接管的那個可調用實體,但是不知道是如何實現的,這裡可以看出他的實現是非常簡單的,也就是從它的傳入參數(_Any_data類型數據)將可調用實體取出,並強制轉換為合法的類型,裡面用到瞭std::__addressof,作用就是即使目標變量(類)存在operator&的重載,也依然能夠獲得變量的地址。
    • 關於std::__addressof的詳細內容可以看這篇文章《C++11的std::addressof源碼解析》
    • _M_manager函數:該函數就是根據傳入的第三個參數來確定執行不同的功能,其餘的幾個函數無非就是涉及到內存的分配和釋放之類的,對我們理解std::function的影響不大,這裡就不展開講瞭
  • 接下來看一下_Function_base::_Ref_manager類
    • 可以看到該類繼承於_Function_base::_Base_manager類,可見他擁有_Function_base::_Base_manager類實現的所有功能
    • 該類是處理當std::function接管的是一個引用包裝類的情況的,為什麼這種情況需要單獨處理呢?因為此時如果直接對傳入參數取地址,取到的將是引用包裝類的地址,而不是我們要接管的可調用對象的地址,所以隻能搞這麼一個特化版本,就像_Function_base::_Ref_manager類做的那樣,裡面的_M_init_functor函數通過使用reference_wrapper的get方法獲取到瞭std::function接管的可調用對象的真實地址
  • _Function_base類裡的其它方法就不講瞭,大傢自己看一下吧,其餘的實現基本都是基於前面講的那些內容,比較簡單

4、總結

本文先是簡單介紹瞭std::function的用途(對C++中各種可調用實體進行封裝),然後通過對源碼進行詳細分析,我們知道瞭std::function是如何實現對可調用實體進行封裝的,源碼內容會比較復雜,但是其中的設計思路是很值得我們學習借鑒的,尤其是與std::reference_wrapper和std::mem_fn配合的那部分代碼更是精妙絕倫。
讀者如果不清楚std::reference_wrapper和std::mem_fn的作用的話,是不可能完全看懂std::function的源代碼的,所以這裡再次建議大傢先看完下面兩篇文章再來學習std::function相關內容:

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

到此這篇關於淺談C++11的std::function源碼解析的文章就介紹到這瞭,更多相關C++11 std::function內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: