I'm attempting to write a an observer pattern in c++
so I have a map that contains eventname -> vector of callback functions
The callback functions are stored in a vector as
std::function<void(void *)>
so the map looks like
std::unordered_map<std::string, std::vector<std::function<void(void *)>>>
I can add listeners to the vector and receive and respond to event notifications. My problem is with implementing detach.
So std::function's can't be compared, so erase/remove is out, so I wanted to search the vector and compare manually.
I found that this question had success using std::function::target with getting access to underlying pointers, but I can't use this, since I'm using std::bind to initialize the callback:
std::function<void(void *)> fnCallback = std::bind(&wdog::onBark, this, std::placeholders::_1)
I just want to compare the underlying member function ptrs, or even comparison with the underlying object ptr to which the member function is associated. Is there any way?
I'd like to avoid wrapping the member fn ptr in an object that contains a hash, although it looks like I might have to go that way...
When I do this, I return a token to the listening code.
My usual pattern is to have a weak_ptr<function<sig>> in the broadcaster, and the token is a shared_ptr<void> (to the stored weak ptr).
When broadcasting, I filter out dead targets, then broadcast. Targets deregister by simply clearing, destroying or otherwise discarding their token. A vector of tokens in their instance is a reasonable way if they want to never deregister.
If you never broadcast this can lead to old dead resources hanging around needlessly, so in a public framework I might want something with bettter guarantees. But it is lightweight easy and fast otherwise.
Related
I'm currently trying to implement an event manager in C++. In principle it keeps a map of event types (uint64_t) to a list of boost::function<void(const IEventDataPtr&)>s.
User can register new listeners by calling EventManager::add(boost::function<void(const IEventDataPtr&)> delegate, EventType event). However, a user might want to deregister their listener later. This would involve finding this particular function object and removing it from the respective list.
I know that boost::function is generally not comparable. When playing around in the debugger I found that by comparing functor.members.func_ptr I could actually do what I was trying to do. It works as expected for lambdas, boost::bind, static member functions and regular functions. Is this safe to do? Are there any gotchas?
My expectation would be for the same object (i.e. the same lambda, function, etc. pp.) to have the same address, that is not shared with others.
I have a fairly generic work queue. It takes some number of std::function<void(void)> and executes them on N worker threads. Closures + type erasure working well.
Now however, I would like the functions to "return" some state, and I would prefer the queue know nothing about what the types might be. To that end, I am considering using a queue of
std::function <std::function<void(void)>(void)>
Which, if I can keep the syntax straight, is a function taking void and returning a function taking void and returning void. The idea being to add a second work queue to return the result of the task execution.
This doesn't strictly solve the problem though - I can then call the returned value, but this doesn't obviously allow me to retrieve the state.
I could return boost::any, which doesn't appear to tell me what the contained type is, or boost::variant which means providing the task library with a list of all possible return types. Neither seem ideal.
What I would like to do is encode the information required to interpret the result of the function call within the functor, but I do not see a clean way to achieve this. Bundling an execute() and an extract() method into a single void(void) functor is beyond my cunning.
An alternative workaround is a heterogenous work queue, but such a thing is also quite a pain to write in C++. I feel optimistic that there is an idiomatic solution for getting at the unknown type that results from executing type erased code, but guessing the search keywords has not gone well for me. Guidance would be appreciated.
edit: An outline of the intended workflow for the application code, as distinct from the work queue / thread pool layer
Construct one or more tasks to execute asynchronously
Package the tasks as std::function</*consistent type*/>
Push onto queue provided by a library
Do some other things for a while
Retrieve an opaque type of some sort from the queue
Pass this opaque type to a function that works out what it actually is
All is well from here
edit: As suggested in the comments, type erasure goes both ways.
Let the generic functor be:
struct functor
{
typedef std::function<void(void)> functype;
functype async;
functype result;
};
Then use an instance of queue<functor> for both send and receive. Async gets run on a remote thread. When an instance of functor comes back we have no idea what it represents, but the result() member does and can perform whatever next step is considered reasonable. This will probably suffice.
(Copying from my comment):
Instead of having step 6 know the precise concrete type, what about solving your problem by using either dynamic or static polymorphism instead?
I am currently experimenting with writing an event queue in C++11. I am using std::bind to obtain std::function objects which are called when certain events happen. The code for this roughly looks like this:
class A
{
public:
void handle();
};
class B { ... };
// Later on, somewhere else...
std::vector< std::function< void() > functions;
A a;
B b;
functions.push_back( std::bind( &A::handle, &a ) );
functions.push_back( std::bind( &B::handle, &b ) );
// Even later:
for( auto&& f : functions )
f(); // <--- How do I know whether f is still "valid"?
Is there any way to guarantee the validity of the function object so that I can avoid stumbling over undefined behaviour here?
I have already taken a look at this question here, std::function to member function of object and lifetime of object, but it only discussed whether deleting a pointer to a bound object raises undefined behaviour. I am more interested in how to handle the destruction of such an object. Is there any way to detect this?
EDIT: To clarify, I know that I cannot guarantee a lifetime for non-static, non-global objects. It would be sufficient to be notified about their destruction so that the invalid function objects can be removed.
As #Joachim has stated, no lifetime is associated to the member function (it's a code section, not data). So you're asking if there is a way to know if the object still exists prior to execute the callback call.
You've to make a sort of framework, where the object dctor notify the container when it is destroyed, so the container could delete it from its "observers", the vector containing all the objects. To do that, the object must memorize in its instance the ptr to the container.
UPDATE
#Jason talks about the use of shared_ptr. It's okay to use them, but in this case, is not addressing the case of HOW to destroy the object linked in other object-notification list. Shared_ptr postponed the destruction of an instance until all "managed" references to it are deleted. But if you need to destroy object A, AND delete all reference to it because that object MUST be deleted, you've to look into all containers that store a shared_ptr and remove it. A very painful activity. The simplest solution (using raw ptr or shared_ptr, if you can use them, is irrelevant) is a two-link connection between the observer and the observed, in such way each one can notify its destruction to the other. How to store this information? many ways to accomplish it: hash tables, slots in observer, etc
One hack/workaround that achieves the desired result would be to use a parameter of type std::shared_ptr. When the bind is destructed, so is the shared pointer - which will do the right thing when it is the last reference. However this involves changes to the signature used. To make it slightly less awkward, you can use static methods that take in a std::shared_ptr this - sort of like the self parameter concept in python, if you are familiar.
Or if you are fine with C++11, you can just use a lambda capture of the shared pointer.
You'd need to dynamically allocate the instances to use this method.
I'm working on a game (and my own custom engine). I have quite a few assets (textures, skeletal animations, etc.) that are used by multiple models and therefore get loaded multiple times.
At first, my ambitions were smaller, game simpler and I could live with a little duplication, so shared_ptr which took care of resource cleanup once the last instance was gone seemed like a good idea. As my game grew, more and more resources got loaded multiple times and all the OpenGL state changing slowed the performance down to a crawl. To solve this problem, I decided to write an asset manager class.
I'm using an unordered_map to store a path to file in std::string and c++11's shared_ptr pointing to the actual loaded asset. If the file is already loaded, I return the pointer, if not, I call the appropriate Loader class. Plain and simple.
Unfortunately, I can't say the same about removal. One copy of the pointer remains in the unordered_map. Currently, I iterate through the entire map and perform .unique() checks every frame. Those pointers that turn out to be unique, get removed from the map, destroying the last copy and forcing the destructor run and do the cleanup.
Iterating through hundreds or thousands of objects is not the most efficient thing to do. (it's not a premature optimization, I am in optimization stage now) Is it possible to somehow override the shared pointer functionality? For example, add an "onLastRemains" event somehow? Maybe I should iterate through part of the unordered_map every frame (by bucket)? Some other way?
I know, I could try to write my own reference counted asset implementation, but all current code I have assumes that assets are shared pointers. Besides, shared pointers are excellent at what they do, so why re-invent the wheel?
Instead of storing shared_ptrs in the asset manager's map(see below, use a regular map), store weak_ptrs. When you construct a new asset, create a shared_ptr with a custom deleter which calls a function in the asset manager which tells it to remove this pointer from it's map. The custom deleter should contain the iterator into the map of this asset and supply that iterator when telling the asset manager to delete it's element from the map. The reason a weak_ptr is used in the map is that any subsequent requests for this element can still be given a shared_ptr (because you can make one from a weak_ptr) but the asset manager doesn't actually have ownership of the asset and the custom deleter strategy will work.
Edit: It was noted below the above technique only works if you use a std::map not a std::unordered_map. My recommendation would be to still do this, and switch to a regular map.
Use a std::unique_ptr in your unordered_map of assets.
Expose a std::shared_ptr with a custom deleter that looks up said pointer in the unordered_map, and either deletes it, or moves it to a second container "to be deleted later". Remember, std::shared_ptr does not have to actually own the data in question! The deleter can do any arbitrary action, and can even be stateful.
This lets you keep O(1) lookups for your assets, bunch cleanup (if you want to) instead of doing cleanup in the middle of other scenes.
You can even support temporary 0 reference count without deleting as follows:
Create a std::make_shared in the unordered_map of assets.
Expose custom std::shared_ptr. These hold a raw T* in the data, and the deleter holds a copy of the std::shared_ptr in the asset map. It "deletes" itself by storing the name (which it also holds) into a central "to be deleted" list.
Then go over said "to be deleted" list and check if they are indeed unique() -- if not, it means someone else in the meantime has spawned one of the "child" std::shared_ptr< T*, std::function<void(T*)>>s.
The only downside to this is that the type of exposed std::shared_ptr is no longer a simple std::shared_ptr.
Perhaps something like this?
shared_ptr<assed> get_asset(string path) {
static map<string, weak_ptr<asset>> cache;
auto ap = cache[path].lock();
if(!ap) cache[path] = ap = load_asset(path);
return ap;
}
The question is strictly about std::function and not boost::function. See the Update section at the bottom of this question for more details, especially the part about it not being possible to compare non-empty std::function objects per the C++11 standard.
The C++11 std::function class template is great for maintaining a collection of callbacks. One can store them in a vector, for example and invoke them when need be. However, maintaining these objects and allowing for unregistration seems to be impossible.
Let me be specific, imagine this class:
class Invoker
{
public:
void Register(std::function<void()> f);
void Unregister(std::function<void()> f);
void InvokeAll();
private:
// Some container that holds the function objects passed to Register()
};
Sample usage scenario:
void foo()
{
}
int main()
{
std::function<void()> f1{foo};
std::function<void()> f2{[] {std::cout << "Hello\n";} };
Invoker inv;
// The easy part
// Register callbacks
inv.Register(f1);
inv.Register(f2);
// Invoke them
inv.InvokeAll();
// The seemingly impossible part. How can Unregister() be implemented to actually
// locate the correct object to unregister (i.e., remove from its container)?
inv.Unregister(f2);
inv.Unregister(f1);
}
It is fairly clear how the Register() function can be implemented. However, how would one go about implementing Unregister(). Let's say that the container that holds the function objects is vector<std::function<void()>> . How would you find a particular function object that is passed to the Unregister() call? std::function does supply an overloaded operator==, but that only tests for an empty function object (i.e., it cannot be used to compare two non-empty function objects to see if they both refer to the same actual invocation).
I would appreciate any ideas.
Update:
Ideas so far mainly consist of the addition of a cookie to be associated with each std::function object that can be used to unregister it. I was hoping for something that is not exogenous to the std::function object itself. Also, there seems to be much confusion between std::function and boost::function. The question is strictly about std::function objects, and not boost::function objects.
Also, you cannot compare two non-empty std::function objects for equality. They will always compare non-equal per the standard. So, links in the comments to solutions that do just that (and use boost::function objects to boot) are patently wrong in the context of this question.
Since you can't test for element identity in the container, it's probably best to use a container (such as std::list) whose iterators do not invalidate when the container is modified, and return iterators back to registering callers that can be used to unregister.
If you really want to use vector (or deque), you could return the integral index into the vector/deque when the callback is added. This strategy would naturally require you to make sure indexes are usable in this fashion to identify the function's position in the sequence. If callbacks and/or unregistration is rare, this could simply mean not reusing spots. Or, you could implement a free list to reuse empty slots. Or, only reclaim empty slots from the ends of the sequence and maintain a base index offset that is increased when slots are reclaimed off the beginning.
If your callback access pattern doesn't require random access traversal, storing the callbacks in a std::list and using raw iterators to unregister seems simplest to me.
I have an idea for this.
Store the callbacks as std::weak_ptr<std::function<void(argtype1, argtype1)>>. Then the caller is responsible for keeping the corresponding std::shared_ptr alive, and all the caller has to do to unregister the callback is destroy all active std::shared_ptrs to the callback function.
When invoking callbacks, the code has to be careful to check for lock failures on the std::weak_ptr<>s it is using. When it runs across these it can remove them from its container of registered callbacks.
Note that this does not give complete thread safety, as the callback invoker can lock the std::weak_ptr and make a temporarily newly active std::shared_ptr of the callback function that can stay alive after the caller's std::shared_ptr goes out of scope.