Verify std :: function before calling?

I am trying to program a simple but flexible event system (basically, as an exercise, I know that there are existing libraries that have really good event handlers), and I came across a little stumbling block.

How can you check if a std::functiondelegate (possibly via lambda, perhaps though std :: bind) is a valid function / if the object for the member function still exists before it is called? I tried just using the std::function'sbool operator , but did not succeed.

Ideally, I would like A. to check somewhere other than the delegate function, and B. still has the code in action when the std :: function being checked is not a delegate.

Any ideas?

Edit: Here is the source for the test in which I ran

#include <iostream>
#include <string>
#include <functional>

class Obj {
public:
    std::string foo;
    Obj(std::string foo) : foo(foo) {}
    std::function<void()> getDelegate() {
        auto callback = [this]() {this->delegatedFn();};
        return callback;
    }
    void delegatedFn() {
        std::cout << foo << std::endl;
    }
};

int main() {
    Obj* obj = new Obj("bar");
    std::function<void()> callback = obj->getDelegate();
    callback();
    delete obj;

    //perform some type of check here whether function is valid, without needing to know whether the function is a delegate or not
    if(callback) {
        std::cout << "Callback is valid" << std::endl; //callback is still considered valid after obj is deleted
        callback(); //no exception thrown, prints a random series of characters
    }
    else {
        std::cout << "Callback is invalid" << std::endl;
    }

    return 0;
}
+4
source share
2 answers

Instead of bare, you can use smart pointers ( std::shared_ptr/ std::weak_ptr):

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

class Obj {
public:
    std::string foo;
    Obj(std::string foo) : foo(foo) {}
    void delegatedFn() {
        std::cout << foo << std::endl;
    }
};

int main() {
    auto obj = std::make_shared<Obj>("bar");
    std::weak_ptr<Obj> ptr = obj;
    std::function<void()> callback = [ptr](){
        auto sh = ptr.lock();
        if(sh) { std::cout << "valid" << std::endl; sh->delegatedFn(); }
        else { std::cout << "invalid" << std::endl; }
    };
    callback();
    obj = nullptr;
    callback(); 
    return 0;
}

In this case, you do not check the validity of the value std::function(this is true when you assign it, even if something captures the dangling pointer).
Instead, you verify that the referenced object is still alive from the function itself.

+4
source

The multiplier / listener used is as follows:

template<class...Args>
struct broadcaster {
  std::vector< std::weak_ptr< std::function<void(Args...)> > > callbacks;

  void operator()(Args...args) const {
    std::remove_erase_if( begin(callbacks), end(callbacks), [](auto&& ptr){return !ptr;} );
    auto tmp = callbacks;
    for (auto pf : tmp) {
      if (pf && *pf) (*pf)(args...);
    }
  }
  std::shared_ptr<void> listen( std::shared_ptr<std::function<void(Args...)>> f ) {
    callbacks.push_back(f);
    return f;
  }

  std::shared_ptr<void> listen( std::function<void(Args...)> f ) {
    auto ptr = std::make_shared<std::function<void(Args...)>>(std::move(f));
    return listen(ptr);
  }
};

Listen to .listentheir callback message using broadcaster. They return the token shared_ptr<void>.

, .

Obj std::vector<std::shared_ptr<void>> tokens, std::shared_ptr<void>. , .

Obj shared_from_this.

std::function<void()> delegate;
std::shared_ptr<std::function<void()>> getDelegatedFn() {
  if (!delegate) delegate = [this]{ this->delegateFn(); }
  return {
    &delegate,
    shared_from_this()
  };
}

Obj ( shared_ptr). listen .

+2

Source: https://habr.com/ru/post/1657061/


All Articles