Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to change the delete action on an existing instance of shared_ptr

Tags:

c++

I have a function where I want a cleanup action done 90% of the time, but in 10% I want some other action to be done.

Is there some way to use some standard scoped control likeshared_ptr<> so that initially it can have one delete action and then later in the function the delete action can be changed?

shared_ptr<T> ptr( new T, std::mem_fun_ref(&T::deleteMe) );
ptr.pn.d = std::mem_fun_ref(&T::queueMe);
like image 754
Greg Domjan Avatar asked Jul 09 '10 17:07

Greg Domjan


Video Answer


2 Answers

Not really - the standard for shared_ptr is written in such a way that the Deleter may be stored by value in control node (a special object that contains the reference counter, holds deleter, tracks weak pointers etc). The deleter is type-erased, but if you know the concrete deleter type somehow, you can use std::get_deleter<Deleter, T>(t). With it you may access the deleter and change its state. Example:

struct A {};

struct deleter {
    void operator()(A* a) {delete a; }
    int m_state;
};

std::shared_ptr<A> ptr(new A(), deleter{});

std::get_deleter<deleter>(ptr)->m_state = 5;

And if you use just a function pointer for all deleters, then yes you can completely replace it, as all potential deleters use the same signature.

(Yes I know the question is 9 years old, but I've just faced this problem in 2020 and solved it like this. The possible reason for it is wrapping C pointers and objects from legacy code that manage ownership through raw pointers)

like image 107
smitsyn Avatar answered Nov 16 '22 02:11

smitsyn


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

struct A {
    ~A() {
        std::cout << "~A()" << std::endl;
    }
};

using DeleterCb = std::function<void(A* p)>;

struct ADeleter {
 public:
    explicit ADeleter(DeleterCb cb) :
        mDeleterCb(cb) {}
    ADeleter() = delete;
    ~ADeleter() = default;

    void operator()(A *a) {
        mDeleterCb(a);
    }
    
    void setDeleterCb(DeleterCb cb) {
        mDeleterCb = cb;
    }

 private:
    DeleterCb mDeleterCb;
};

int main() {
    auto sp = std::shared_ptr<A>(new A{},
        ADeleter([](A *p){
            delete p;
            std::cout << "deleter_1" << std::endl;
        })
    );
    
    std::get_deleter<ADeleter>(sp)->setDeleterCb(
        [](A *p){
            delete p;
            std::cout << "deleter_2" << std::endl;
        }
    );
}
like image 32
mewo1234 Avatar answered Nov 16 '22 02:11

mewo1234