Wednesday, March 23, 2011

make shared_ptr not use delete

in my code i would like boost::shared_ptr not to call delete but call ptr->deleteMe() instead.

Also i have a few C styled functions that return a ptr. Can i make it call lib_freeXYZ(ptr); instead of trying to delete?

From stackoverflow
  • You can give the shared_ptr template a custom deleter function which has the signature

      void Deleter( T* ptr);
    

    for a boost::shared_ptr

    So for Deleter you would do

      boost::shared_ptr<T> ptrToT( new T, Deleter );
    

    then in the body of Deleter:

       void Deleter( T* ptr);
       {
            ptr->deleteMe();
            // And make sure YOU ACTUALLY DELETE (or do whatever else you need to
            // do to release the resource)
            delete ptr;
       }
    

    For your specific case when you need something simple (like ptr->deleteMe) see Greg's solution, its very nice.

    Johannes Schaub - litb : i had a similar case where i had to prevent shared_ptr to call delete - it was because the object was allocated statically. may be interesting: http://stackoverflow.com/questions/363453/looking-for-a-better-c-class-factory#363543
  • For the C-style data, do as @Doug. T suggested.

    For your class, why not do cleanup in a destructor? Even if this is including deleteMe() in the destructor.

    Greg Domjan : Perhaps there are some boundary issues? calling delete in a different module could be bad, especially if it is using a different crt instance.
    Kris Kumler : Indeed. In that case, an overloaded delete operator?
  • Doug T. answered your question nicely. I'll tell you about intrusive_ptr. Maybe you can use it in your project too.

    If you have some C library that has already reference counting, but you have to manually call those functions, you can use boost::intrusive_ptr too, and provide proper definitions for its add_ref and release functions. intrusive_ptr will find and call them. They are responsible to increment the reference count and decrement it, freeing the resource when necassary:

    void intrusive_ptr_add_ref(foo *f) {
        lib_add_ref(f);
    }
    
    void intrusive_ptr_release(foo *f) {
        if(lib_dec_ref(f) == 0) 
            lib_free(f);
    }
    

    Then you can just create objects from raw pointers of type foo*. intrusive_ptr will call your functions when its copied/destructed:

    intrusive_ptr<foo> f(lib_alloc());
    
    // can wrap raw pointers too, which already may be referenced somewhere else
    foo *p = get_foo_from_somewhere();
    function_taking_intrusive_ptr(p);
    
  • Or how about using the stl to provide the wrapper functor - Doug T. description but without the custom caller.

    boost::shared_ptr<T> ptr( new T, std::mem_fun_ref(&T::deleteMe) );
    boost::shared_ptr<S> ptr( new S, std::ptr_fun(lib_freeXYZ) );
    
    Doug T. : I actually prefer this, more elegant.

0 comments:

Post a Comment