I see many posts when I google this problem. I wonder, since most of them are dated 1.35 and previous, if there was ever a solution to this problem? I think this fellow says it best when he posted, "My problem is, that when i bind member functions, if i specify the instance of the class as a shared_ptr, then i get memory leaks because the binding's shared_ptr to the instance keeps it alive, and it potentially produces cyclic references that in the current model, would be complicated to break. And of course, if i use raw pointers to the binding instances, then i'll get a crash if the instance has been destroyed and i try to execute the binding function. So what i would need, is to use bind with weak pointers, and just do nothing if locking it fails." http://www.gamedev.net/topic/494089-help-boostbind-and-shared-pointers/ I've almost went to just using raw pointers and letting the program crash if the instance to which the member bound no longer exists. I hate to do that.
I see many posts when I google this problem. I wonder, since most of them are dated 1.35 and previous, if there was ever a solution to this problem?
I think this fellow says it best when he posted, "My problem is, that when i bind member functions, if i specify the instance of the class as a shared_ptr, then i get memory leaks because the binding's shared_ptr to the instance keeps it alive, and it potentially produces cyclic references that in the current model, would be complicated to break.
And of course, if i use raw pointers to the binding instances, then i'll get a crash if the instance has been destroyed and i try to execute the binding function.
So what i would need, is to use bind with weak pointers, and just do nothing if locking it fails."
http://www.gamedev.net/topic/494089-help-boostbind-and-shared-pointers/
I've almost went to just using raw pointers and letting the program crash if the instance to which the member bound no longer exists. I hate to do that.
Have you looked at the link I posted as an answer to one of your previous questions on the subj? http://article.gmane.org/gmane.comp.lib.boost.user/70699 Doesn't it do exactly what you want?
Igor R
I see many posts when I google this problem. I wonder, since most of them
are
dated 1.35 and previous, if there was ever a solution to this problem?
I think this fellow says it best when he posted, "My problem is, that when i bind member functions, if i specify the instance of the class as a shared_ptr, then i get memory leaks because the binding's shared_ptr to the instance keeps it alive, and it potentially produces cyclic references that in the current model, would be complicated to break.
And of course, if i use raw pointers to the binding instances, then i'll get a crash if the instance has been destroyed and i try to execute the binding function.
So what i would need, is to use bind with weak pointers, and just do nothing if locking it fails."
http://www.gamedev.net/topic/494089-help-boostbind-and-shared-pointers/
I've almost went to just using raw pointers and letting the program crash if the instance to which the member bound no longer exists. I hate to do that.
Have you looked at the link I posted as an answer to one of your previous questions on the subj? http://article.gmane.org/gmane.comp.lib.boost.user/70699 Doesn't it do exactly what you want?
I read the article. Sadly, I cannot even begin to follow the code. I also tried going back to raw pointers and now I get unhandled exceptions rather than the problem with destructors not getting called :/ I am debugging that now and trying to track it down. What a pain. So, boost has not built this in yet then, even though there seems to be an aweful lot of demand for it?
I read the article. Sadly, I cannot even begin to follow the code.
What article? I posted a *ready-to-use* code there, including main() to test it. You don't have to follow it, just copy&paste it. (But the code is really short and simple, so if you feel it's unclear you're welcome to ask.)
I also tried going back to raw pointers and now I get unhandled exceptions
Of course you'll get segfaults if you access destroyed objects! What I meant there is that you can use raw pointer *tracking* it with a separate weak_ptr. But again, if you think it's too much overhead for your design - just copy&paste&use the above code.
So, boost has not built this in yet then, even though there seems to be an aweful lot of demand for it?
I believe it's just not too generic. Note that it "does nothing" and returns a default-constructed result type, when the weak_ptr expires. It may be appropriate for your specific case, but it's definitely not generic. HTH, Igor'.
I believe it's just not too generic. Note that it "does nothing" and returns a default-constructed result type, when the weak_ptr expires. It may be appropriate for your specific case, but it's definitely not generic.
...but it could be made better and more consistent with weak_ptr behavior, if instead of "doing nothing" it would throw boost::bad_weak_ptr.
Igor R
I read the article. Sadly, I cannot even begin to follow the code.
What article? I posted a *ready-to-use* code there, including main() to test it. You don't have to follow it, just copy&paste it. (But the code is really short and simple, so if you feel it's unclear you're welcome to ask.)
The link you gave. It contains a couple template classes, from what I understand overload operator ->*(), which I've never even seen before. I assume it is simply trying to replace the internals of the shared_ptr.
I also tried going back to raw pointers and now I get unhandled exceptions
Of course you'll get segfaults if you access destroyed objects!
Yes, obviously. The problem is predicting when they will be destroyed and making sure all outstanding bound calls have already been completed and are done with.
What I meant there is that you can use raw pointer *tracking* it with a separate weak_ptr.
It wouldn't matter if I tracked it or not. Sure, I can check if the pointer is good before I hand a bind to boost::asio::io_service. I can check it again when io_service calls me back. However, the crash is going to occur when io_service actually does the callback and I have no control there.
But again, if you think it's too much overhead for your design - just copy&paste&use the above code.
I absolutly cannot cut and paste code that I don't understand into a company project. It is probably simple to you, because you understand the internals of the various boost objects. I do not. I am also overdue for a working solution.
So, boost has not built this in yet then, even though there seems to be an aweful lot of demand for it?
I believe it's just not too generic. Note that it "does nothing" and returns a default-constructed result type, when the weak_ptr expires. It may be appropriate for your specific case, but it's definitely not generic.
I understand the claim that it would be up to the user on how to handle the instance no longer existing. Maybe they want to throw an exception, maybe they want to do nothing, etc. However, I don't see a way to even be _informed_ of the situation in order to handle it at all. At least not without a workaround like what you posted. It's not in the boost library itself.
The link you gave. It contains a couple template classes, from what I understand overload operator ->*(), which I've never even seen before. I assume it is simply trying to replace the internals of the shared_ptr.
No, it doesn't replace any internals and doesn't hack anything. The code just extends bind functionality at its extension point. I'll explain and I'm sure you'll be convinced it's quite simple. First of all, in order to be able to bind a smart-pointer (or a pointer-like object), one should provide get_pointer() free function that accepts a smart-ptr and returns a raw pointer - or, to be more exact, returns *something* that supports "pointer-to-member" operator ->*. Out of the box, boost provides get_pointer for shared_ptr, auto_ptr, optional, intrusive_ptr and some other types, making them bindable. The same way you can make other smart pointers bindable, like ATL::CComPtr, etc. So, just to make weak_ptr bindable, you could add the following trivial lines: namespace boost { template<class T> T *get_pointer(const weak_ptr<T> &weak) { return weak.lock().get(); } } But this wouldn't solve the whole problem, as expired weak_ptr's get() returns empty shared_ptr, whose get() returns null pointer. Although, null pointer would crash your code in a more consistent and nice way :). This means that instead of raw pointer we should return some "adapter", which supports operator ->*, and tests whether it holds null or not. Operator ->*, in turn, by definition must return a "callable", i.e. an object or a function, which can be called with the appropriate arguments. This is exactly what "ptr_adapter" and "invoker" classes do: ptr_adapter stores the raw ptr, and when its operator ->* is being invoked with a specific member function (during the binder invocation) it constructs and returns "invoker" instance, which holds both raw ptr to the object and the pointer to the member function that should be called. Now, the invoker's operator() just tests whether it holds null ptr or not and performs the actual invocation of the member function.
What I meant there is that you can use raw pointer *tracking* it with a separate weak_ptr.
It wouldn't matter if I tracked it or not. Sure, I can check if the pointer is good before I hand a bind to boost::asio::io_service. I can check it again when io_service calls me back. However, the crash is going to occur when io_service actually does the callback and I have no control there.
I'm afraid you misunderstand what "tracking" is. Testing smart-ptr when you create the binder certainly doesn't help - it should be test just before the *invocation*. So, you should pass such a tracking object to the entity that is supposed to invoke your functor. When this entity invokes your functor, it should first lock & test the tracking object: auto locked = weak.lock(); if (locked) invokeTheFunctor(); Of course, if the caller is not your own module, but asio::io_service, you cannot use this technique without defining additional wrapers.
I understand the claim that it would be up to the user on how to handle the instance no longer existing. Maybe they want to throw an exception, maybe they want to do nothing, etc. However, I don't see a way to even be _informed_ of the situation in order to handle it at all. At least not without a workaround like what you posted. It's not in the boost library itself.
Being informed is exactly the problem here :). The only reasonable way to inform is to throw an exception, which means that bind invocation process will loose its "no-throw" guarantee (which I belive, currently does exist).
participants (2)
-
Christopher Pisz
-
Igor R