The idea of @pmjordan was already going in the right direction. You replied that you can't use shared_ptr because you can't take ownership back from it once constructed. But that is not entirely correct: with shared_ptr s custom deleter mechanism, you can.
This is how: Assume these toy defintions for your A and f(A*) : struct A { ~A() { std::cout void operator()( T * t ) { if ( m_delete ) delete t; } } Then you can write a take() function that takes ownership of the shared_ptr payload again: template T * take( const boost::shared_ptr & sp ) { opt_delete * d = boost::get_deleter( sp ); assert( d ); assert( d->m_delete == true ); d->m_delete = false; return sp.get(); } (this will leave the payload in the remaining shared_ptr instances, but for your case, that's ok, and the assert() s cover the cases when it's not) Now you can manually wrap f(A*) like this: void f_sp( const boost::shared_ptr & a ) { f( take( a ) ); } And finally, test the two scenarios: int main( int argc, char * argv ) { const boost::shared_ptr a( new A, opt_delete() ); const boost::function func = boost::bind( &f_sp, a ); if ( argc >= 2 && *argv1 == '1' ) // call 'func' func(); else ; // don't return 0; } Executing the test program with a 1 argument will print in f(A*) ~A() and without (or any other argument), it will print ~A() You can extend the test harness to put func into a container first, but it'll still be safe. The only thing that isn't safe in the case is calling the func copies more than once (but then you'll trigger the second assertion in take() ) EDIT : Note that this mechanism isn't thread-safe. To make it thread-safe, you need to supply opt_delete with a mutex to synchronise operator() with take().
The idea of @pmjordan was already going in the right direction. You replied that you can't use shared_ptr, because you can't take ownership back from it once constructed. But that is not entirely correct: with shared_ptr's custom deleter mechanism, you can.
This is how: Assume these toy defintions for your A and f(A*): struct A { ~A() { std::cout void operator()( T * t ) { if ( m_delete ) delete t; } }; Then you can write a take() function that takes ownership of the shared_ptr payload again: template T * take( const boost::shared_ptr & sp ) { opt_delete * d = boost::get_deleter( sp ); assert( d ); assert( d->m_delete == true ); d->m_delete = false; return sp.get(); } (this will leave the payload in the remaining shared_ptr instances, but for your case, that's ok, and the assert()s cover the cases when it's not). Now you can manually wrap f(A*) like this: void f_sp( const boost::shared_ptr & a ) { f( take( a ) ); } And finally, test the two scenarios: int main( int argc, char * argv ) { const boost::shared_ptr a( new A, opt_delete() ); const boost::function func = boost::bind( &f_sp, a ); if ( argc >= 2 && *argv1 == '1' ) // call 'func' func(); else ; // don't return 0; } Executing the test program with a 1 argument will print in f(A*) ~A() and without (or any other argument), it will print ~A() You can extend the test harness to put func into a container first, but it'll still be safe. The only thing that isn't safe in the case is calling the func copies more than once (but then you'll trigger the second assertion in take()).
EDIT: Note that this mechanism isn't thread-safe. To make it thread-safe, you need to supply opt_delete with a mutex to synchronise operator() with take().
1: I like this answer. I suspected that a good solution should use custom deleters, and thought in this direction; what I forgot is that deleter can be a functor, and so each object can have its own flag. – Alexey Kukanov May 16 at 5:36.
Using a shared_ptr (or, less likely, a C++98 std::auto_ptr) should solve your lifecycle problem. Alternatively, if you can't change f itself, you could create a wrapper which accepts a shared_ptr, pulls out the raw pointer and calls f with it. If you find yourself writing a lot of these wrappers, you may be able to create a template for generating them, assuming the function signatures are similar.
I can change f(), but can not change A* to shared_ptr. I tried to change A* to auto_ptr, but boost:bind() and auto_ptr are not good friends lists.boost. Org/Archives/boost/2002/10/38652.
Php - I need to do boost::bind(boost::ref(auto_ptr_a)), but I can't ensure auto_ptr_a will outlive boost:bind – dimba May 11 at 12:26 I generally don't recommend using auto_ptr except for unusual circumstances. What's the problem with using shared_ptr, exactly? – pmjordan May 11 at 13:44 f() is very nested function, part of legacy code.It handles A* pointer memory manually.
Since there's no way to release() shared_ptr, I can not use it. In contrast, auto_ptr I can release right in the beginning of f(). – dimba May 11 at 13:55 What do you mean by there's no way to release a shared_ptr?
Use boost::shared_ptr pA(new A()); to allocate memory on the HEAP and then pA.reset() to release it. – karlphillip May 11 at 14:08 1 I'm confused. If f() frees the memory explicitly, I don't see why you need automatic memory management at all.
Won't binding the raw pointer directly work fine then? – pmjordan May 11 at 14:48.
NB! This is UGLY! Have just scrateched some proof of concept.
Well, it does what requested, as far as I can see - but this stuff relies on const_cast assumption. If you decide to use something like that in your program, be ready to double check all copy constructions happening in your program all the time, and using valgrind to verify nothing is leaked/corrupted. Trick is in defining you own wrapper class, that ignores const qualifiers and allows auto_ptr ownership transfer from const referenced auto_ptr.
This can get crazy if you ll try, for example, copy vector itself. So be sure to read carefuly about vector copy semantics, auto_ptr ownership transfer semantics and, best of all - just use shared_ptr :) #include #include #include #include #include class parameter_data { public: ~parameter_data() { std::cout callable; std::auto_ptr data; public: storage_wrapper( const storage_wrapper& copy ) { callable = const_cast(copy). Callable; data = const_cast(copy).
Data; } storage_wrapper( parameter_data *adata ) : data( adata ) { callable = boost::bind( &f, adata ); } storage_wrapper& operator=( const storage_wrapper& copy) { callable = const_cast(copy). Callable; data = const_cast(copy). Data; } void operator()() { callable(); } }; int main() { std::cout container; for ( int I = 0; I Push_back( storage_wrapper( new parameter_data() ) ); for ( int I = 0; I.
This is similar to what I had before - container was storing storage_wrapper*, while storage_wrapper d-tor was deleting parameter_data. I try to avoid such manual solution - I want to avoid writing storage_wrapper class – dimba May 11 at 16:58 Please ignore my previous comment - I wasn't unable to edit it. This is similar to what I had before - storage_wrapper was holding parameter_data* and in its d-tor was deleting parameter_data*, while container was storing storage_wrapper*.
At time of container destruction, code was iterating all elements and deleting them. Your solution has more robust memory management. Hoverer, I'm trying to do it even more and do not have storage_wrapper class at all.So code will remain only with essentially parts - container, parameter_data and callback in form of boost::bind – dimba May 11 at 17:11 Well, I hardly can imagine any way to it without writing some small wrapper - stuff you want breaks some safety rules about automatic ownership manipulation.
I doubt there can be any library solution that provides hacky way. My code has additional benefit that you can release ownership of auto_ptr before calling f() in operator() of wrapper - and that will allow f() to release memory itself without modifying f() at all. – Михаил Страшун May 11 at 17:29.
It doesn't need to be very complex: class MyContainer : public std::vector > { public: void push_back(boost::function f, A *pA) { push_back(f); vec. Push_back(pA); } ~MyContainer() { int s=vec. Size; for(int i=0;i vec; }; It has one problem that you need to pass it to other functions via MyContainer & instead of std::vector reference, otherwise the original push_back can be called and it allows for cases where you can push_back without providing the A* pointer.
Also it has no check for bind parameters to be the same A* object than pA. You can fix that by changing the push_back prototype: template void push_back(T *object, void (T::*fptr)(), A *pA) { push_back(boost::bind(fptr, object, pA)); vec. Push_back(pA); }.
Hmm, one idea for fixing some problems with this solution is to make the inheritance private. But then it's all about wrapping solution. It still doesn't work with insert() functions etc, so this solution is slightly bad, depending on how you use std::vector's interface in your program.
– tp1 May 15 at 18:37 see EDIT 02 - I can put callbacks to container with different types and number of arguments. Than I don't think proposed by you solution will fit. – dimba May 15 at 20:21 oh, that's slightly more difficult as boost::function does not support it.
You'll need something like class I { virtual void *data(int num)const=0; virtual std::string type(int num) const=0; }; and then use std::vector vec; and typeid(T).name(); and then implement it as described in the push_back solution. The implementation should have constructor with proper parameters. – tp1 May 15 at 22:48.
Lets say I have heap allocated A*, which I want to pass as argument to boost::bind. Boost::bind is saved for later processing in some STL like container of boost::functions's. I want to ensure A* will be destroyed at destruction of the STL container.
How can it be done?
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.