Is there a way to change the delete action on an existing instance of shared_ptr
I have a function where I want a cleanup action do开发者_开发知识库ne 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);
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)
I don't think you can change the deleter once the shared_ptr
was created.
But why would you do that ? Usually, when you create an object, you know immediatly how it must be destroyed. This is not likely to change.
If you really must do some specific treatments, you still can provide a custom deleter which does special things depending on the required logic.
There is a valid reason to need to change the deleter. Take this for example:
int foo( std::shared_ptr<double>& bar ) {
...
std::shared_ptr<double> p( my_allocator<double>::allocate(), my_deleter<double>() );
bar.swap(p); // this copies the deleter
...
}
int main( int, char** ) {
std::shared_ptr<double> d;
foo( d ); // d now has a new deleter that will be called when it goes out of scope
...
}
In this case the foo() function allocates a double* using some special allocator. It needs to free that memory in a special way also. The caller shouldn't need to know how to free the memory.
#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;
}
);
}
This doesn't make any sense, since there is any number of shared_ptr
s managing the ownership of the value. You'd need to modify them all, and that's not feasible. Let's not forget that a control block is an implementation detail, so going "aha, but change it in the control block" won't work.
The delete actions should be controlled by the instance owned by shared_ptr
, e.g.
class C {
...
void (C::action*)() { &C::action1 };
void action1();
void action2();
~C() { (this->*action)(); }
};
void test() {
std::shared_ptr<C> a;
a->action = &C::action2;
// action2 gets invoked once `a` falls out of scope
}
精彩评论