Fixation à un ptr faible

Est-il possible d' std::bind pour un std::weak

7 ответов

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

Vous ne devriez jamais faire cela. Jamais.

MyClass::CallbackFunc est une fonction de membre non statique de la classe MyClass. Une fonction membre statique, c' être appelé avec un valide exemple MyClass.

total pointweak_ptr c'est qu'il n'est pas nécessairement valide. Vous pouvez détecter sa validité en la transformant en une shared_ptr et ensuite tester si le pointeur est NULL. Depuis weak_ptr n'est pas garanti pour être valide en tout temps, vous ne peut pas appeler une fonction de membre non statique avec un.

Ce que vous faites n'est pas plus valable que:

std::bind(&MyClass::CallbackFunc, nullptr)

il peut se compiler, mais il finira par se planter quand vous essayez de l'appeler.

votre meilleur pari est d'utiliser la logique actuelle, de ne pas appeler la fonction de rappel si le weak_ptr n'est pas valide. bind n'est pas conçu pour faire de la logique; il fait juste exactement ce que vous lui dites: appel de la fonction. Vous devez donc utiliser un lambda approprié:

std::weak_ptr<MyClass> thisWeakPtr(shared_from_this());
return std::function<void()>([thisWeakPtr]()
{
  auto myPtr = thisWeakPtr.lock();
  if(myPtr)
    myPtr->CallbackFunc()
});
10
répondu Nicol Bolas 2016-12-11 19:35:38
la source

j'ai été capable de créer des weak_pointers de std::function et je l'ai testé avec clang-3.2 (vous n'avez donné aucune restriction de compilateur).

#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;
}

La sortie est:

~/projects/stack_overflow> clang++-mp-3.2 --std=c++11 --stdlib=libc++ weak_fun.cpp -o wf && ./wf
Func here.
SharedFunc here.
WeakFunc here.
Your backing pointer went away, sorry.
1
répondu Tim Finer 2012-07-30 19:36:37
la source
#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;
}

sortie:

abc
bad_weak_ptr
1
répondu pal 2015-04-30 15:15:25
la source

je sais que c'est une vieille question, mais j'ai la même exigence et je suis sûr que je ne suis pas seul.

la solution à la fin pour moi était de retourner un objet de fonction qui renvoie un boost:: optionnel< > selon que la fonction a été appelée ou non.

code ici:

#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)...)
        };
    }
}}

appelé (par exemple) comme suit:

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));


}
https://github.com/madmongo1/valuelib

1
répondu Richard Hodges 2016-02-09 19:52:50
la source

Je ne sais pas pourquoi cette définition n'est pas dans boost. Il doit y avoir une bonne raison (comment traiter avec lock fail? Est-ce que lancer de là est acceptable? La sécurité des threads? De toute façon, ça validera votre appel.

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;
};

une autre solution:

vous pouvez envelopper la fonction std::. La classe produisant le callback tiendrait un shared_ptr< wrapper_type > et fournirait un weak_ptr< wrapper_type >. La production de l'objet serait l'un avec la propriété, si elle est hors de portée, les appelants ne seront pas en mesure de promouvoir leur faible référence. Votre type de wrapper pourrait transférer les arguments d'appel vers la fonction std::ou simplement l'exposer via son interface. Assurez-vous juste que sur la copie vous manipulez correctement le shared_ptr sur le wrapper (ne partagez pas).

template< typename _Ty >
struct wrapper
{
  wrapper(_Ty wrappe) 
    : _wrappe(wrappe)
  { }

  _Ty _wrappe;
};

...
boost::shared_ptr< wrapper < std::func< ... > > _func(new wrapper < std::func< ... > );

...
boost::weak_ptr< wrapper < std::func< ... > getCallBack() {
  return _func;
}
0
répondu regu 2012-09-02 00:47:15
la source

Comment à ce sujet? il ne fonctionne que pour les actions std::function<void()> mais peut-être peut-on le généraliser pour des fonctions paramétrées arbitrairement.

#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);
}

voici un exemple d'utilisation:

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
}
0
répondu Aviad Rozenhek 2012-09-10 18:53:25
la source

Vous pouvez lier weak_ptr pour la fonction en tant que l'un des paramètres,

et vérifiez quand la fonction est appelée.

Par exemple:

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.
  // ...
}
0
répondu ALittleDiff 2014-11-17 09:15:30
la source

Autres questions sur c++ callback bind weak-ptr std-function