Search code examples
c++shared-ptrenable-shared-from-this

smart pointer as argument of function which uses std::function, std::bind


#include <functional>
#include <iostream>
#include <memory>

template <typename T>
struct Message
{
    T a;
};

template <typename T>
class Connection : public std::enable_shared_from_this<T>
{
  typedef std::function<void(Message<T>&)> msg_handle;
  public:
    void SetHandle(msg_handle handle)
    {
      handle_ = handle;
    }
    void Run()
    {
      Message<T> t;
      std::cout << "Run() from Connection" << std::endl;
      handle_(t);
    }

  private:
    msg_handle handle_;
};

template <typename T>
class Server
{
  public:
    void OnMessage(Message<T>& msg, std::shared_ptr<Connection<T>> remote)
    {
      std::cout << "OnMessage() from Server" << std::endl;
    }
};


int main()
{
  std::shared_ptr<Server<int>> server = std::make_shared<Server<int>>();
  std::shared_ptr<Connection<int>> connection = std::make_shared<Connection<int>>();
  connection->SetHandle(std::bind(&Server<int>::OnMessage, server, std::placeholders::_1, connection));
  connection->Run();
  return 0;
}

Error:

E:\Qt\Tools\mingw730_64\lib\gcc\x86_64-w64-mingw32\7.3.0\include\c++\bits\shared_ptr.h:661: error: no matching function for call to 'std::weak_ptr<int>::_M_assign(Connection<int>*&, const std::__shared_count<>&)'
In file included from E:/Qt/Tools/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/memory:81:0,
                 from C:/Boost/include/boost-1_72/boost/asio/associated_allocator.hpp:19,
                 from C:/Boost/include/boost-1_72/boost/asio.hpp:20,
                 from D:\StudyDisk\Applications\QT\test_boost_connection\main.cpp:2:
E:/Qt/Tools/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/bits/shared_ptr.h: In instantiation of 'void std::enable_shared_from_this<_Tp>::_M_weak_assign(_Tp1*, const std::__shared_count<>&) const [with _Tp1 = Connection<int>; _Tp = int]':
E:/Qt/Tools/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/bits/shared_ptr_base.h:1373:6:   required from 'typename std::enable_if<std::__shared_ptr<_Tp, _Lp>::__has_esft_base<_Yp2>::value>::type std::__shared_ptr<_Tp, _Lp>::_M_enable_shared_from_this_with(_Yp*) [with _Yp = Connection<int>; _Yp2 = Connection<int>; _Tp = Connection<int>; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2; typename std::enable_if<std::__shared_ptr<_Tp, _Lp>::__has_esft_base<_Yp2>::value>::type = void]'
E:/Qt/Tools/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/bits/shared_ptr_base.h:1301:35:   required from 'std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<Connection<int> >; _Args = {}; _Tp = Connection<int>; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2]'
E:/Qt/Tools/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/bits/shared_ptr.h:344:64:   required from 'std::shared_ptr<_Tp>::shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<Connection<int> >; _Args = {}; _Tp = Connection<int>]'
E:/Qt/Tools/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/bits/shared_ptr.h:690:14:   required from 'std::shared_ptr<_Tp> std::allocate_shared(const _Alloc&, _Args&& ...) [with _Tp = Connection<int>; _Alloc = std::allocator<Connection<int> >; _Args = {}]'
E:/Qt/Tools/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/bits/shared_ptr.h:706:39:   required from 'std::shared_ptr<_Tp> std::make_shared(_Args&& ...) [with _Tp = Connection<int>; _Args = {}]'
D:\StudyDisk\Applications\QT\test_boost_connection\main.cpp:50:83:   required from here
E:/Qt/Tools/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/bits/shared_ptr.h:661:4: error: no matching function for call to 'std::weak_ptr<int>::_M_assign(Connection<int>*&, const std::__shared_count<>&)'
  { _M_weak_this._M_assign(__p, __n); }
    ^~~~~~~~~~~~

I don't understand. Help pls!!!


Solution

  • std::enable_shared_from_this requires you specify the type of the class that is to be enabled, and is deriving.

    You mistakenly specify T, when the class you are enabling is Connection<T>.

    The error is pointing out (indirectly) that the hidden weak_ptr member has the wrong type.

    Simply put, this needs to be your class template definition

    template <typename T>
    class Connection : public std::enable_shared_from_this<Connection<T>>
    {
    //...
    };