C++ 绑定到弱ptr

C++ 绑定到弱ptr,c++,callback,bind,weak-ptr,std-function,C++,Callback,Bind,Weak Ptr,Std Function,是否有方法将std::绑定到std::weak\u ptr?我想存储一个“弱函数”回调,当被调用方被销毁时,它会自动“断开”连接 我知道如何使用共享的ptr创建std::函数: std::function<void()> MyClass::GetCallback() { return std::function<void()>(std::bind(&MyClass::CallbackFunc, shared_from_this())); } std::函

是否有方法将std::绑定到std::weak\u ptr?我想存储一个“弱函数”回调,当被调用方被销毁时,它会自动“断开”连接

我知道如何使用共享的ptr创建std::函数:

std::function<void()> MyClass::GetCallback()
{
    return std::function<void()>(std::bind(&MyClass::CallbackFunc, shared_from_this()));
}
std::函数MyClass::GetCallback()
{
返回std::function(std::bind(&MyClass::CallbackFunc,shared_from_this());
}
但是,返回的std::函数使我的对象永远保持活动状态。所以我想把它绑定到一个弱\u ptr

std::function<void()> MyClass::GetCallback()
{
    std::weak_ptr<MyClass> thisWeakPtr(shared_from_this());
    return std::function<void()>(std::bind(&MyClass::CallbackFunc, thisWeakPtr));
}
std::函数MyClass::GetCallback()
{
std::weak_ptr thisWeakPtr(共享_from_this());
返回std::function(std::bind(&MyClass::CallbackFunc,thiswakptr));
}
但这并不能编译。(std::bind将不接受弱ptr!)有什么方法可以绑定到弱ptr吗

我发现了关于这方面的讨论(见下文),但似乎没有标准的实现。存储“弱功能”的最佳解决方案是什么,特别是在Boost不可用的情况下


讨论/研究(所有这些都使用Boost,且未标准化):

  • (还有一个例子)
  • 另一个

我能够创建std::function的弱指针,并使用clang-3.2对其进行了测试(您没有给出任何编译器限制)

下面是一个示例应用程序,它创建并测试我认为您需要的内容:

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

typedef std::function<void(void)> Func;
typedef std::shared_ptr<Func> SharedFunc;
typedef std::weak_ptr<Func> WeakFunc;


void Execute( Func f ) {
    f();
}


void Execute( SharedFunc sf ) {
    (*sf)();
}


void Execute( WeakFunc wf ) {
    if ( auto f = wf.lock() )
        (*f)();
    else
        std::cout << "Your backing pointer went away, sorry.\n";
}

int main(int, char**) {

    auto f1 = [](){ std::cout << "Func here.\n"; };
    Execute( f1 );

    auto f2 = [](){ std::cout << "SharedFunc here.\n"; };
    SharedFunc sf2( new Func(f2) );
    Execute( sf2 );

    auto f3 = [](){ std::cout << "WeakFunc here.\n"; };
    SharedFunc sf3( new Func(f3) );
    WeakFunc wf3( sf3 );
    Execute( wf3 );

    // Scoped test to make sure that the weak_ptr is really working.
    WeakFunc wf4;
    {
        auto f4 = [](){ std::cout << "You should never see this.\n"; };
        SharedFunc sf4( new Func(f4) );
        wf4 = sf4;
    }
    Execute( wf4 );

    return 0;
}

我不知道为什么boost中没有这个定义。无论如何,必须有一个很好的理由(如何处理锁失败?从那里抛出是否可以接受?线程安全?)来验证被调用方

namespace boost {

template<class T> T * get_pointer(boost::weak_ptr<T> const& p)
{
  boost::shared_ptr< T > _strong = p.lock();
  if( _strong )
   return _strong.get();
  else
    throw 1;
}

}

int main(int arg, char *argv[])
{
  boost::weak_ptr< MyType > weak_bad;
  {
    boost::shared_ptr< MyType > strong(new MyType);
    boost::weak_ptr< MyType > weak(strong);
    boost::function< void(int) > _func1 = boost::bind(&MyType::setX, weak, _1);
    _func1(10);
    weak_bad = strong;
  }

  try {
    boost::function< void(int) > _func1 = boost::bind(&MyType::setX, weak_bad, _1);
    _func1(10);
  }
  catch(...)
  {
    std::cout << "oops!";
  }

  return 0;
};
namespace boost{
模板T*get_指针(boost::weak_ptr const&p)
{
boost::shared_ptr_strong=p.lock();
如果(强)
return_strong.get();
其他的
投掷1枚;
}
}
int main(int arg,char*argv[]
{
boost::弱\u ptr弱\u坏;
{
boost::shared_ptrstrong(新的MyType);
boost::弱_ptr弱(强);
boost::function\u func1=boost::bind(&MyType::setX,弱,\u 1);
_职能1(10);
弱=强;
}
试一试{
boost::function\u func1=boost::bind(&MyType::setX,弱\u坏,\u 1);
_职能1(10);
}
捕获(…)
{
std::cout并提供一个弱的\u ptr。生成对象将是具有所有权的对象,如果它超出范围,调用方将无法提升其弱引用。您的包装类型可以将调用参数转发给std::函数,或者只需通过其接口公开它。只需确保在复制时正确处理包装器上的共享\u ptr(不共享)

模板
结构包装器
{
包装纸
:_wrappe(wrappe)
{ }
_蒂乌拉佩;
};
...
boost::shared_ptr\u func(新的wrapper);
...
boost::weak_ptrgetCallBack(){
返回函数;
}
它可能会编译,但当您试图调用它时,它最终会崩溃

最好使用实际逻辑,如果
弱ptr
无效,则不调用回调函数。
bind
不是设计用于执行逻辑的;它只执行您告诉它的操作:调用函数。因此,您需要使用适当的lambda:

std::weak_ptr<MyClass> thisWeakPtr(shared_from_this());
return std::function<void()>([thisWeakPtr]()
{
  auto myPtr = thisWeakPtr.lock();
  if(myPtr)
    myPtr->CallbackFunc()
});
std::weak_ptr thisWeakPtr(来自_this()的共享_);
返回std::函数([thisWeakPtr]()
{
auto myPtr=thiswakptr.lock();
if(myPtr)
myPtr->CallbackFunc()
});

这如何?它只适用于操作
std::function
,但可能可以推广到任意参数化函数

#include <memory>
#include <functional>

template<typename T>
void 
perform_action_or_ignore_when_null(
    std::weak_ptr<T> weak, 
    std::function< void( std::shared_ptr<T> ) > func
    )
{
    if(auto ptr = weak.lock())
        func(ptr);
}

template<typename T>
std::function<void()> 
ignore_when_null(
    std::weak_ptr<T> weak, 
    std::function< void( std::shared_ptr<T> ) > func
    )
{
    return std::bind(perform_action_or_ignore_when_null<T>, weak, func);
}
#包括
#包括
模板
无效的
当为空时执行\u操作\u或\u忽略\u(
标准::弱\u ptr弱,
std::functionfunc
)
{
if(auto ptr=weak.lock())
func(ptr);
}
模板
std::函数
当\u为空时忽略\u(
标准::弱\u ptr弱,
std::functionfunc
)
{
返回std::bind(当为空、弱、func时执行操作或忽略);
}
下面是一个示例用法:

struct Foo {
    Foo() {}
    void bar() { 
        std::cout << "hello world!" << std::endl;
    }
};

void main()
{
  std::weak_ptr<Foo> weakfoo;
  std::function<void(std::shared_ptr<Foo>)> foobar = std::bind(&Foo::bar, std::placeholders::_1);
  {
     auto foo = std::make_shared<Foo>();
     weakfoo  = foo;

     auto f = ignore_when_null(weakfoo, foobar);
     f(); // prints "hello world!";
   }

   auto g = ignore_when_null(weakfoo, foobar);
   g(); // does nothing
}
structfoo{
Foo(){}
空条({

std::cout您可以将
弱\u ptr
作为参数之一绑定到函数,
并在调用函数时检查它

例如:

std::function<void()> MyClass::GetCallback()
{
    std::weak_ptr<MyClass> thisWeakPtr(shared_from_this());
    return std::function<void()>(std::bind(&MyClass::CallbackFunc, this,
                                           thisWeakPtr));
}

void MyClass::CallbackFunc(const std::weak_ptr<MyClass>& thisWeakPtr)
{
  if (!thisWeakPtr.lock()) {
    return;
  }

  // Do your callback job.
  // ...
}
std::函数MyClass::GetCallback()
{
std::weak_ptr thisWeakPtr(共享_from_this());
返回std::function(std::bind(&MyClass::CallbackFunc,this,
这是个弱点);
}
void MyClass::CallbackFunc(const std::weak\ptr和thiswakptr)
{
如果(!thisWeakPtr.lock()){
返回;
}
//做回叫工作。
// ...
}

我知道这是一个老问题,但我有同样的要求,我相信我并不孤单

对我来说,最终的解决方案是返回一个函数对象,该对象返回一个boost::optional,具体取决于函数是否被调用

代码如下:

#include <boost/optional.hpp>
#include <memory>

namespace value { namespace stdext {

    using boost::optional;
    using boost::none;

    struct called_flag {};

    namespace detail
    {
        template<class Target, class F>
        struct weak_binder
        {
            using target_type = Target;
            using weak_ptr_type = std::weak_ptr<Target>;

            weak_binder(weak_ptr_type weak_ptr, F f)
            : _weak_ptr(std::move(weak_ptr))
            , _f(std::move(f))
            {}

            template<class...Args,
            class Result = std::result_of_t<F(Args...)>,
            std::enable_if_t<not std::is_void<Result>::value>* = nullptr>
            auto operator()(Args&&...args) const -> optional<Result>
            {
                auto locked_ptr = _weak_ptr.lock();
                if (locked_ptr)
                {
                    return _f(std::forward<Args>(args)...);
                }
                else
                {
                    return none;
                }

            }

            template<class...Args,
            class Result = std::result_of_t<F(Args...)>,
            std::enable_if_t<std::is_void<Result>::value>* = nullptr>
            auto operator()(Args&&...args) const -> optional<called_flag>
            {
                auto locked_ptr = _weak_ptr.lock();
                if (locked_ptr)
                {
                    _f(std::forward<Args>(args)...);
                    return called_flag {};
                }
                else
                {
                    return none;
                }

            }

            weak_ptr_type _weak_ptr;
            F _f;
        };
    }

    template<class Ret, class Target, class...FuncArgs, class Pointee, class...Args>
    auto bind_weak(Ret (Target::*mfp)(FuncArgs...), const std::shared_ptr<Pointee>& ptr, Args&&...args)
    {
        using binder_type = decltype(std::bind(mfp, ptr.get(), std::forward<Args>(args)...));
        return detail::weak_binder<Target, binder_type>
        {
            std::weak_ptr<Target>(ptr),
            std::bind(mfp, ptr.get(), std::forward<Args>(args)...)
        };
    }
}}
#包括
#包括
命名空间值{namespace stdext{
使用boost::可选;
使用boost::none;
名为_flag{}的结构;
名称空间详细信息
{
模板
结构弱黏结剂
{
使用target_type=target;
使用弱\u ptr\u type=std::弱\u ptr;
弱粘合剂(弱粘合剂类型弱粘合剂,F)
:_弱_ptr(标准::移动(弱_ptr))
,_f(标准::移动(f))
{}
模板
自动运算符()(Args&&…Args)常量->可选
{
自动锁定\u ptr=\u弱\u ptr.lock();
如果(锁定)
{

return _f(std::forward

也许一个信号库(比如Boost.Signals2)能满足你的需要。@LucDanton:嗯,是的,你是对的。如果是这样的话,弱_fn是否还存在任何用例?你是否尝试过使用接受共享_ptr的弱_ptr构造函数?@TimFiner:我知道如何从共享_ptr创建弱_ptr.)问题是std::function构造函数不能接受弱\u ptr。我正在尝试传递弱_
#include <memory>
#include <functional>

template<typename T>
void 
perform_action_or_ignore_when_null(
    std::weak_ptr<T> weak, 
    std::function< void( std::shared_ptr<T> ) > func
    )
{
    if(auto ptr = weak.lock())
        func(ptr);
}

template<typename T>
std::function<void()> 
ignore_when_null(
    std::weak_ptr<T> weak, 
    std::function< void( std::shared_ptr<T> ) > func
    )
{
    return std::bind(perform_action_or_ignore_when_null<T>, weak, func);
}
struct Foo {
    Foo() {}
    void bar() { 
        std::cout << "hello world!" << std::endl;
    }
};

void main()
{
  std::weak_ptr<Foo> weakfoo;
  std::function<void(std::shared_ptr<Foo>)> foobar = std::bind(&Foo::bar, std::placeholders::_1);
  {
     auto foo = std::make_shared<Foo>();
     weakfoo  = foo;

     auto f = ignore_when_null(weakfoo, foobar);
     f(); // prints "hello world!";
   }

   auto g = ignore_when_null(weakfoo, foobar);
   g(); // does nothing
}
std::function<void()> MyClass::GetCallback()
{
    std::weak_ptr<MyClass> thisWeakPtr(shared_from_this());
    return std::function<void()>(std::bind(&MyClass::CallbackFunc, this,
                                           thisWeakPtr));
}

void MyClass::CallbackFunc(const std::weak_ptr<MyClass>& thisWeakPtr)
{
  if (!thisWeakPtr.lock()) {
    return;
  }

  // Do your callback job.
  // ...
}
#include <iostream>
#include <string>
#include <memory>
#include <functional>
using namespace std;

template < typename T > class LockingPtr {
    std :: weak_ptr < T > w;
public:
    typedef shared_ptr < T > result_type;
    LockingPtr ( const std :: shared_ptr < T > & p ) : w ( p ) { }
    std :: shared_ptr < T > lock ( ) const {
        return std :: shared_ptr < T > ( w );
    }
    std :: shared_ptr < T > operator-> ( ) const {
        return lock ( );
    }
    template < typename ... Args > std :: shared_ptr < T > operator( ) ( Args ... ) const {
        return lock ( );
    }
};

template < typename T > LockingPtr < T > make_locking ( const shared_ptr < T > & p ) {
    return p;
}

namespace std {
    template < typename T > struct is_bind_expression < LockingPtr < T > > :
        public true_type { };
}

int main() {
    auto p = make_shared < string > ( "abc" );
    auto f = bind ( & string :: c_str, make_locking ( p ) );
    cout << f ( ) << '\n';
    p.reset ( );
    try {
    cout << f ( ) << '\n';
    } catch ( const exception & e ) {
        cout << e.what ( ) << '\n';
    }
    // your code goes here
    return 0;
}
abc
bad_weak_ptr
#include <boost/optional.hpp>
#include <memory>

namespace value { namespace stdext {

    using boost::optional;
    using boost::none;

    struct called_flag {};

    namespace detail
    {
        template<class Target, class F>
        struct weak_binder
        {
            using target_type = Target;
            using weak_ptr_type = std::weak_ptr<Target>;

            weak_binder(weak_ptr_type weak_ptr, F f)
            : _weak_ptr(std::move(weak_ptr))
            , _f(std::move(f))
            {}

            template<class...Args,
            class Result = std::result_of_t<F(Args...)>,
            std::enable_if_t<not std::is_void<Result>::value>* = nullptr>
            auto operator()(Args&&...args) const -> optional<Result>
            {
                auto locked_ptr = _weak_ptr.lock();
                if (locked_ptr)
                {
                    return _f(std::forward<Args>(args)...);
                }
                else
                {
                    return none;
                }

            }

            template<class...Args,
            class Result = std::result_of_t<F(Args...)>,
            std::enable_if_t<std::is_void<Result>::value>* = nullptr>
            auto operator()(Args&&...args) const -> optional<called_flag>
            {
                auto locked_ptr = _weak_ptr.lock();
                if (locked_ptr)
                {
                    _f(std::forward<Args>(args)...);
                    return called_flag {};
                }
                else
                {
                    return none;
                }

            }

            weak_ptr_type _weak_ptr;
            F _f;
        };
    }

    template<class Ret, class Target, class...FuncArgs, class Pointee, class...Args>
    auto bind_weak(Ret (Target::*mfp)(FuncArgs...), const std::shared_ptr<Pointee>& ptr, Args&&...args)
    {
        using binder_type = decltype(std::bind(mfp, ptr.get(), std::forward<Args>(args)...));
        return detail::weak_binder<Target, binder_type>
        {
            std::weak_ptr<Target>(ptr),
            std::bind(mfp, ptr.get(), std::forward<Args>(args)...)
        };
    }
}}
TEST(bindWeakTest, testBasics)
{

    struct Y
    {
        void bar() {};
    };

    struct X : std::enable_shared_from_this<X>
    {

        int increment(int by) {
            count += by;
            return count;
        }

        void foo() {

        }

        Y y;

        int count = 0;
    };

    auto px = std::make_shared<X>();

    auto wf = value::stdext::bind_weak(&X::increment, px, std::placeholders::_1);
    auto weak_call_bar = value::stdext::bind_weak(&Y::bar, std::shared_ptr<Y>(px, &px->y));

    auto ret1 = wf(4);
    EXPECT_TRUE(bool(ret1));
    EXPECT_EQ(4, ret1.get());

    auto wfoo1 = value::stdext::bind_weak(&X::foo, px);
    auto retfoo1 = wfoo1();
    EXPECT_TRUE(bool(retfoo1));

    auto retbar1 = weak_call_bar();
    EXPECT_TRUE(bool(retbar1));

    px.reset();
    auto ret2 = wf(4);
    EXPECT_FALSE(bool(ret2));

    auto retfoo2 = wfoo1();
    EXPECT_FALSE(bool(retfoo2));

    auto retbar2 = weak_call_bar();
    EXPECT_FALSE(bool(retbar2));


}