Delete raw pointer argument to boost::bind - c++

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.
To demostrate:
A* pA = new A();
// some time later
container.push_back(boost::bind(&SomeClass::HandleA, this, pA);
// some time later
container is destroyed => pA is destroyed too
How can it be done?
EDIT
Maybe what I want is not that realistic.
I have raw pointer and function which receives the raw pointer. The call is delayed by means of boost::bind. At this point I want automatic memory management in case boost::bind want executed. I'm lazy, so I want to use "ready" smart-pointer solution.
std::auto_ptr looks like a good candidate, however ...
auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, pAutoA);
doesn't compile (see here)
auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, boost::ref(pAutoA));
pAutoA is destroyed, deleting underlying pA.
EDIT 02
In the mentioned container I will need to store misc "callbacks" with different arguments. Some of them are raw pointers to object. Since the code is old, I not always can change it.
Writing own wrapper for storing callbacks in container is last resort (while maybe the only one), hence bounty.

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 << "~A()" << std::endl; }
};
void f( A * a ) {
std::cout << "in f(A*)" << std::endl;
delete a;
}
Write a deleter that can be "switched off":
struct opt_delete {
bool m_delete;
opt_delete() : m_delete( true ) {}
template <typename T>
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 <typename T>
T * take( const boost::shared_ptr<T> & sp ) {
opt_delete * d = boost::get_deleter<opt_delete>( 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> & a ) {
f( take( a ) );
}
And finally, test the two scenarios:
int main( int argc, char * argv[] ) {
const boost::shared_ptr<A> a( new A, opt_delete() );
const boost::function<void()> func =
boost::bind( &f_sp, a );
if ( argc >= 2 && *argv[1] == '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().

I assume you mean you have some function, let's call it f() which takes an A*, which you then proxy with boost::bind? Can you change this function to accept a Boost/TR1 shared_ptr<A> instead? 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<A>, 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.

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 <iostream>
#include <boost/bind.hpp>
#include <algorithm>
#include <vector>
#include <boost/function.hpp>
class parameter_data
{
public:
~parameter_data()
{
std::cout << "~parameter_data()" << std::endl;
}
parameter_data()
{
std::cout << "parameter_data()" << std::endl;
}
};
void f( parameter_data* data )
{
std::cout << "Processing data..." << std::endl;
};
class storage_wrapper
{
private:
boost::function<void()> callable;
std::auto_ptr<parameter_data> data;
public:
storage_wrapper( const storage_wrapper& copy )
{
callable = const_cast< storage_wrapper&>(copy).callable;
data = const_cast< storage_wrapper&>(copy).data;
}
storage_wrapper( parameter_data *adata )
: data( adata )
{
callable = boost::bind( &f, adata );
}
storage_wrapper& operator=( const storage_wrapper& copy)
{
callable = const_cast< storage_wrapper&>(copy).callable;
data = const_cast< storage_wrapper&>(copy).data;
}
void operator()()
{
callable();
}
};
int main()
{
std::cout << "Start of program" << std::endl;
{
std::vector<storage_wrapper> container;
for ( int i = 0; i < 100; i++ )
container.push_back( storage_wrapper( new parameter_data() ) );
for ( int i = 0; i < 100; i++ )
container[i]();
}
std::cout << "End of program" << std::endl;
return 0;
}

It doesn't need to be very complex:
class MyContainer : public std::vector<boost::function<void ()> > {
public:
void push_back(boost::function<void ()> f, A *pA)
{ push_back(f); vec.push_back(pA); }
~MyContainer()
{ int s=vec.size; for(int i=0;i<s;i++) delete vec[i]; }
private:
std::vector<A*> 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<class T>
void push_back(T *object, void (T::*fptr)(), A *pA)
{
push_back(boost::bind(fptr, object, pA)); vec.push_back(pA);
}

Related

Array of polymorphic objects

I commonly come across the need to create arrays or vectors of polymorphic objects. I'd usually prefer to use references, rather than smart pointers, to the base class because they tend to be simpler.
Arrays and vectors are forbidden from containing raw references, and so I've tended to use smart pointers to the base classes instead. However, there is also the option to use std::reference_wrapper instead: https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper
From what I can tell from the documentation, this is what one of its intended uses is, but when the topic of arrays containing polymorphic objects comes up, the common advice seems to be to use smart pointers rather than std::reference_wrapper.
My only thought is that smart pointers may be able to handle the lifetime of the object a little neater?
TL:DR; Why are smart pointers, such as std::unique_ptr seemingly preferred over std::reference_wrapper when creating arrays of polymorphic objects?
In very simple terms:
unique_ptr is the owner of the object. It manages the lifetime of the owned object
reference_wrapper wraps a pointer to an object in memory. It does NOT manage the lifetime of the wrapped object
You should create an array of unique_ptr (or shared_ptr) to guarantee the release of the object when it's not needed anymore.
If you are sufficiently motiviated, you can write a poly_any<Base> type.
A poly_any<Base> is an any restricted to only storing objects that derive from Base, and provides a .base() method that returns a Base& to the underlying object.
A very incomplete sketch:
template<class Base>
struct poly_any:private std::any
{
using std::any::reset;
using std::any::has_value;
using std::any::type;
poly_any( poly_any const& ) = default;
poly_any& operator=( poly_any const& ) = default;
Base& base() { return get_base(*this); }
Base const& base() const { return const_cast<Base const&>(get_base(const_cast<poly_any&>(*this))); }
template< class ValueType,
std::enable_if_t< /* todo */, bool > =true
>
poly_any( ValueType&& value ); // todo
// TODO: sfinae on ValueType?
template< class ValueType, class... Args >
explicit poly_any( std::in_place_type_t<ValueType>, Args&&... args ); // todo
// TODO: sfinae on ValueType?
template< class ValueType, class U, class... Args >
explicit poly_any( std::in_place_type_t<ValueType>, std::initializer_list<U> il,
Args&&... args ); // todo
void swap( poly_any& other ) {
static_cast<std::any&>(*this).swap(other);
std::swap( get_base, other.get_base );
}
poly_any( poly_any&& o ); // todo
poly_any& operator=( poly_any&& o ); // todo
template<class ValueType, class...Ts>
std::decay_t<ValueType>& emplace( Ts&&... ); // todo
template<class ValueType, class U, class...Ts>
std::decay_t<ValueType>& emplace( std::initializer_list<U>, Ts&&... ); // todo
private:
using to_base = Base&(*)(std::any&);
to_base get_base = 0;
};
Then you just have to intercept every means of putting stuff into the poly_any<Base> and store a get_base function pointer:
template<class Base, class Derived>
auto any_to_base = +[](std::any& in)->Base& {
return std::any_cast<Derived&>(in);
};
Once you have done this, you can create a std::vector<poly_any<Base>> and it is a vector of value types that are polymorphically descended from Base.
Note that std::any usually uses the small buffer optimization to store small objects internally, and larger objects on the heap. But that is an implementation detail.
Basically, a reference_wrapper is a mutable reference: Like a reference, it must not be null; but like a pointer, you can assign to it during its lifetime to point to another object.
However, like both pointers and references, reference_wrapper does not manage the lifetime of the object. That's what we use vector<uniq_ptr<>> and vector<shared_ptr<>> for: To ensure that the referenced objects are properly disposed off.
From a performance perspective, vector<reference_wrapper<T>> should be just as fast and memory efficient as vector<T*>. But both of these pointers/references may become dangling as they are not managing object lifetime.
Let's try the experiment:
#include <iostream>
#include <vector>
#include <memory>
#include <functional>
class Base {
public:
Base() {
std::cout << "Base::Base()" << std::endl;
}
virtual ~Base() {
std::cout << "Base::~Base()" << std::endl;
}
};
class Derived: public Base {
public:
Derived() {
std::cout << "Derived::Derived()" << std::endl;
}
virtual ~Derived() {
std::cout << "Derived::~Derived()" << std::endl;
}
};
typedef std::vector<std::reference_wrapper<Base> > vector_ref;
typedef std::vector<std::shared_ptr<Base> > vector_shared;
typedef std::vector<std::unique_ptr<Base> > vector_unique;
void fill_ref(vector_ref &v) {
Derived d;
v.push_back(d);
}
void fill_shared(vector_shared &v) {
std::shared_ptr<Derived> d=std::make_shared<Derived>();
v.push_back(d);
}
void fill_unique(vector_unique &v) {
std::unique_ptr<Derived> d(new Derived());
v.push_back(std::move(d));
}
int main(int argc,char **argv) {
for(int i=1;i<argc;i++) {
if(std::string(argv[i])=="ref") {
std::cout << "vector" << std::endl;
vector_ref v;
fill_ref(v);
std::cout << "~vector" << std::endl;
} else if (std::string(argv[i])=="shared") {
std::cout << "vector" << std::endl;
vector_shared v;
fill_shared(v);
std::cout << "~vector" << std::endl;
} else if (std::string(argv[i])=="unique") {
std::cout << "vector" << std::endl;
vector_unique v;
fill_unique(v);
std::cout << "~vector" << std::endl;
}
}
}
running with argument shared:
vector
Base::Base()
Derived::Derived()
~vector
Derived::~Derived()
Base::~Base()
running with argument unique
vector
Base::Base()
Derived::Derived()
~vector
Derived::~Derived()
Base::~Base()
running with argument ref
vector
Base::Base()
Derived::Derived()
Derived::~Derived()
Base::~Base()
~vector
Explanation:
shared: Memory is shared by different parts of the code. In the example, the Derived object is first owned by the d local var in the function fill_shared() and by the vector. When the code exits the scope of the function object is still owned by the vector and only when the vector goes finally away, the object is deleted
unique: Memory is owned by the unique_ptr. In the example, the Derived object is first owned by the d local var. However it must be moved into the vector, transferring the ownership. Same as before, when the only owner goes away, the object gets deleted.
ref: There's no owning semantics. The object is created as a local variable of the fill_ref() function, and the reference to the object can be added to the vector. However, the vector does not own the memory and when the code goes out of the fill_ref() function, the object goes away, leaving the vector pointing to unallocated memory.

Check validity of std::function before calling?

I'm trying to program a simple but flexible event system (mostly just as an exercise, I know there are existing libraries that have really good event handlers), and I've run into a little stumbling block.
How can you check if an std::function that's a delegate (probably through a lambda, possibly though std::bind) is a valid function/if the object for the member function still exists before calling it? I've tried simply using std::function's bool operator, but haven't had any success.
Ideally I'd like to A. do the checking somewhere other than inside the delegate function, and B. still have the code be valid when the std::function that's being checked isn't a delegate.
Any ideas?
Edit: Here's the source for the test that I ran
#include <iostream>
#include <string>
#include <functional>
class Obj {
public:
std::string foo;
Obj(std::string foo) : foo(foo) {}
std::function<void()> getDelegate() {
auto callback = [this]() {this->delegatedFn();};
return callback;
}
void delegatedFn() {
std::cout << foo << std::endl;
}
};
int main() {
Obj* obj = new Obj("bar");
std::function<void()> callback = obj->getDelegate();
callback();
delete obj;
//perform some type of check here whether function is valid, without needing to know whether the function is a delegate or not
if(callback) {
std::cout << "Callback is valid" << std::endl; //callback is still considered valid after obj is deleted
callback(); //no exception thrown, prints a random series of characters
}
else {
std::cout << "Callback is invalid" << std::endl;
}
return 0;
}
You can use smart pointers (std::shared_ptr/std::weak_ptr) instead of naked ones:
#include <iostream>
#include <string>
#include <functional>
#include <memory>
class Obj {
public:
std::string foo;
Obj(std::string foo) : foo(foo) {}
void delegatedFn() {
std::cout << foo << std::endl;
}
};
int main() {
auto obj = std::make_shared<Obj>("bar");
std::weak_ptr<Obj> ptr = obj;
std::function<void()> callback = [ptr](){
auto sh = ptr.lock();
if(sh) { std::cout << "valid" << std::endl; sh->delegatedFn(); }
else { std::cout << "invalid" << std::endl; }
};
callback();
obj = nullptr;
callback();
return 0;
}
In this case you are not directly checking the validity of a std::function (that is valid when you assign it something, even if that something captures a dangling pointer).
Instead, you check that the referred object is still alive from within the function itself.
The broadcaster/listener pattern I use looks like this:
template<class...Args>
struct broadcaster {
std::vector< std::weak_ptr< std::function<void(Args...)> > > callbacks;
void operator()(Args...args) const {
std::remove_erase_if( begin(callbacks), end(callbacks), [](auto&& ptr){return !ptr;} );
auto tmp = callbacks;
for (auto pf : tmp) {
if (pf && *pf) (*pf)(args...);
}
}
std::shared_ptr<void> listen( std::shared_ptr<std::function<void(Args...)>> f ) {
callbacks.push_back(f);
return f;
}
std::shared_ptr<void> listen( std::function<void(Args...)> f ) {
auto ptr = std::make_shared<std::function<void(Args...)>>(std::move(f));
return listen(ptr);
}
};
Listeners to a message .listen their callback with broadcaster. They get back a shared_ptr<void> token.
So long as that token exists, the broadcaster will send messages at the function object passed in.
Obj would either store a std::vector<std::shared_ptr<void>> tokens or a single std::shared_ptr<void>. When it was destroyed, its listeners would automatically deregister.
Alternatively, Obj could inherit from shared_from_this. Then it implements
std::function<void()> delegate;
std::shared_ptr<std::function<void()>> getDelegatedFn() {
if (!delegate) delegate = [this]{ this->delegateFn(); }
return {
&delegate,
shared_from_this()
};
}
which shares the lifetime of the Obj instance itself (uses the aliasing constructor of shared_ptr). Pass this to listen and done.

C++: How do I pass a function(without knowing its parameters) to another function?

I'm trying to create a function that will store and repeat another function given as a parameter for a specific amount of time or repeats given.
But when you want to pass a function as a parameter you have to know all of its parameters before hand.
How would I do if I wanted to pass the function as one parameter, and the parameters as another?
void AddTimer(float time, int repeats, void (*func), params); // I know params has no type and that (*func) is missing parameters but it is just to show you what I mean
Thanks in advance
The best that you can do is use std::function or boost::function as argument, together with std::bind or boost::bind to, well, bind the arguments with the function:
void foo() { std::cout << "foo" << std::endl; }
void bar( int x ) { std::cout << "bar(" << x << ")" << std::endl; }
struct test {
void foo() { std::cout << "test::foo" << std::endl; }
};
void call( int times, boost::function< void() > f )
{
for ( int i = 0; i < times; ++i )
f();
}
int main() {
call( 1, &foo ); // no need to bind any argument
call( 2, boost::bind( &bar, 5 ) );
test t;
call( 1, boost::bind( &test::foo, &t ) ); // note the &t
}
Note that there is something inherently wrong with passing a fully generic function pointer: how do you use it? How would the body of the calling function look like to be able to pass an undefined number of arguments of unknown types? That is what the bind templates resolve, they create a class functor that stores the function pointer (concrete function pointer) together with copies of the arguments to use when calling (note the &t in the example so that the pointer and not the object is copied). The result of the bind is a functor that can be called through a known interface, in this case it can be bound inside a function< void() > and called with no arguments.
dribeas' answer is correct as far as modern C++ is concerned.
For the sake of interest, there's also a simple lo-tech solution from the C world that as far as it goes, works in C++. Instead of allowing arbitrary parameters, define the function as void (*func)(void*), and make "params" void*. It's then the caller's job to define some struct that will contain the parameters, and manage its lifecycle. Usually the caller would also write a simple wrapper to the function that's really needed to be called:
void myfunc(int, float); // defined elsewhere
typedef struct {
int foo;
float bar;
} myfunc_params;
void myfunc_wrapper(void *p) {
myfunc_params *params = (myfunc_params *)p;
myfunc(params->foo, params->bar);
}
int main() {
myfunc_params x = {1, 2};
AddTimer(23, 5, myfunc_wrapper, &x);
sleep(23*5 + 1);
}
In practice you want to "fire and forget" timers, so if you use this scheme you may also need a way for the timer manage to free the userdata pointer once all firings have completed.
Obviously this has limited type safety. In principle in shouldn't matter, because whoever supplies the function pointer and user data pointer shouldn't have a great deal of difficulty ensuring that they match. In practice of course people find ways to write bugs, and ways to blame you because their compiler didn't tell them about the bugs ;-)
It's just an example how you could pass function pointer to another function, and then call it:
void AddTimer(float time, int repeats, void (*func)(int), int params)
{
//call the func
func(params);
}
void myfunction(int param)
{
//...
}
AddTimer(1000.0, 10, myfunction, 10);
Similarly, you can write your code if your function takes different type or/and numbers of parameters!
If there's really no rules about the function pointer at all, just use void*.
In C++11, things get really simple - you get everything you need to implement your timers.
The most concise way of passing bound function calls is by passing a functor generated using lambda syntax, e.g.: []{ std::cout << "Hello, world!" << std::endl; }. An object thus generated has a type known only to the compiler, but the type is convertible to std::function<void()>.
#include <functional>
#include <list>
#include <chrono>
#include <thread>
#include <iostream>
template <typename Clock = std::chrono::high_resolution_clock>
class Timers {
public:
using clock = Clock;
using duration = typename clock::duration;
using time_point = typename clock::time_point;
private:
struct Timer {
duration const period;
std::function<void()> const call;
int repeats;
time_point next;
Timer(duration $period, int $repeats, std::function<void()> && $call) :
period($period), call(std::move($call)), repeats($repeats) {}
};
std::list<Timer> m_timers;
public:
Timers() {}
Timers(const Timers &) = delete;
Timers & operator=(const Timers &) = delete;
template <typename C> void add(std::chrono::milliseconds period,
int repeats, C && callable)
{
if (repeats) m_timers.push_back(Timer(period, repeats, callable));
}
enum class Missed { Skip, Emit };
void run(Missed missed = Missed::Emit) {
for (auto & timer : m_timers) timer.next = clock::now() + timer.period;
while (! m_timers.empty()) {
auto next = time_point::max();
auto ti = std::begin(m_timers);
while (ti != std::end(m_timers)) {
while (ti->next <= clock::now()) {
ti->call();
if (--ti->repeats <= 0) {
ti = m_timers.erase(ti);
continue;
}
do {
ti->next += ti->period;
} while (missed == Missed::Skip && ti->next <= clock::now());
}
next = std::min(next, ti->next);
++ ti;
}
if (! m_timers.empty()) std::this_thread::sleep_until(next);
}
}
};
int main(void)
{
Timers<> timers;
using ms = std::chrono::milliseconds;
timers.add(ms(1000), 2, []{ std::cout << "Hello, world!" << std::endl; });
timers.add(ms(100), 20, []{ std::cout << "*" << std::endl; });
timers.run();
std::cout << std::endl;
return 0;
}

C++ function pointer

Is there a way in C++ to make an "untyed" function pointer ?
For example:
// pointer to global function
void foo( void (*fptr)() );
// pointer to member
void foo( void (Bar::*fptr)() );
Is there a way I can remove the class on which the member is ? So that I could do something like this:
void foo( void ("any type"::*fptr)(), "same type as for the pointer" &instance );
And then, in foo, I would like to store that pointer in a list, so that I can iterator over the list and call the function/member pointed to, regardless of what class it belongs to. Of course I'd need a list of instances on which to call the function.
Thx.
You can use a template.
template<typename T> void foo( void(T::*)(), T&) { ... }
However, people prefer to go for the function object approach. You can do this dynamically or statically.
void foo(std::function<void()> func) {
// std::bind is used to make this out of a member function
}
template<typename T> void foo(T t = T()) {
t(); // This is the best approach.
}
Edit: Some examples.
void foo(std::function<void()> func) {
std::cout << "In example one ";
func();
}
template<typename T> void foo(T t = T()) {
std::cout << "In example two ";
t();
}
class some_class {
public:
void func() { std::cout << "in ur function!\n"; }
};
int main(void)
{
some_class* ptr = NULL;
struct tempfunctor {
tempfunctor(some_class* newptr)
: ptr(newptr) {}
some_class* ptr;
void operator()() { return ptr->func(); }
};
foo(tempfunctor(ptr)); // Calls example two
foo(std::function<void()>(tempfunctor(ptr))); // Calls example one
foo(std::function<void()>(std::bind(&some_class::func, ptr)); // I'm not that familiar with bind, it looks something similar to this.
std::cin.get();
}
This is the idiom called the function object idiom, used heavily in STL and other high-quality libraries. The compile-time template is cleaner but the std::function can be bound at runtime.
Edit # OP: I didn't quite see your list requirement in there. A std::function<void()> is your best choice here.
The following seems to work fine with g++ and MSVC:
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
using namespace std;
void foo( boost::function<int()> f )
{
cout << "f() = " << f() << endl;
}
template< class Type >
void foo( int (Type::*f)() const, Type const& o )
{
foo( boost::bind( f, boost::ref( o ) ) );
}
int func1() { return 1; }
struct S { int func2() const { return 2; } };
int main()
{
foo( func1 );
foo( &S::func2, S() );
}
Disclaimer: I seldom use the Boost stuff and I just typed the above without bothering to check the docs, so possibly it could be expressed more cleanly.
Also note that C++0x standard library offers the same functionality.
Cheers & hth.,
No. The bound class is an intrinsic part of the member function pointer type.
You can, however, use a member function pointer to a common baseclass, or a template.
Can you use functors in your list?
http://en.wikipedia.org/wiki/Function_object
Have a look at Fast Delegates: http://www.codeproject.com/KB/cpp/FastDelegate.aspx
This is an easy drop-in library that allows you to delegate pretty much anything and at a very high speed.
template <typename T>
void foo( void (T::*fptr)(), T& instance)
{
// ...
}
I'm not going to play expert here, but I think this will work, if not I would like to know why.
You can't have a pointer like that, but you could have a collection of boost::any, and put heterogeneous pointers (or any kind of functors) into it.
You can't do that, and you shouldn't do that even if you could, because it is against the spirit of the language. Create a base class with "fptr" as a pure virtual member, and inherit all your classes from that class.

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 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);
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>(ptr). 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_ptrs 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
}