Binding a callbacks to an expiring shared_ptr? - c++

I am familiar with std::shared_ptr and std::weak_ptr and know how they work. However, I would like the std::shared_ptr to emit a callback, like a boost signal. This would allow std::weak_ptr, who still refer to the deleted object, to be cleaned up right in time.
Is there maybe already some smart pointer implementation, which will report the destruction?
Explanation
I think there might be a small design flaw in std::weak_ptrs, that can lead to false memory leaks. By "false memory leak" I mean an object, that is still accessible by the program, but whose reason of existence is not valid anymore. The difference to a true memory leak is, that the true memory leak is completely unknown by the program, while the false leak is just a part that wasn't cleaned up properly.
Another description can be found at codingwisdom.com
Use Watchers
One of the problems with freeing an object is that you may have done so while other things are still pointing at it. This introduces dangling pointers and crashes! To combat the evil of dangling pointers, I like to use a basic "watcher" system. This is not unlike the weak reference discussed above. The implementation is like this:
Create a base class "Watchable" that you derive from on objects that should broadcast when they're being deleted. The Watchable object keeps track of other objects pointing at it.
Create a "Watcher" smart pointer that, when assigned to, adds itself to the list of objects to be informed when its target goes away.
This basic technique will go a long way toward solving dangling pointer issues without sacrificing explicit control over when an object is to be destroyed.
Example
Let's say we implement the observer pattern using boost Boost Signals2. We have a class Observable, that contains one or more signals and another class Observer, that connects to Observable's signals.
What would happen to Observable's slots, when a observing Observer is deleted? When we do nothing, then the connection would point to nowhere and we would probably receive a segmentation fault, when emitting the signal.
To deal with this issue, boost's slots also offer a method track(const weak_ptr<void>& tracked_object). That means, if I call track and pass a weak_ptr to Observer, then the slot won't be called when the weak_ptr expired. Instead, it will be deleted from the signal.
Where is the problem? Let's we delete an Observer and never call a certain signal of Observable ever again. In this case, the tracked connection will also never be deleted. Next time we emit the signal it will be cleaned up. But we don't emit it. So the connection just stays there and wastes resources.
A solution would be: when owning shared_ptr should emit a signal when it is destroying it's object. This would allow other other objects to clean up right in time. Everything that has a weak_ptr to the deleted object might register a callback and false memory leaks could be avoided.

//
// create a C function that does some cleanup or reuse of the object
//
void RecycleFunction
(
MyClass * pObj
)
{
// do some cleanup with pObj
}
//
// when you create your object and assign it to a shared pointer register a cleanup function
//
std::shared_ptr<MyClass> myObj = std::shared_ptr<MyClass>( new MyClass,
RecycleFunction);
Once the last reference expires "RecyleFunction" is called with your object as parameter. I use this pattern to recycle objects and insert them back into a pool.

This would allow std::weak_ptr, who still refer to the deleted object,
to be cleaned up right in time.
Actually, they only hold weak references, which do not prevent the object from being destroyed. Holding weak_ptrs to an object does not prevent it's destruction or deletion in any fashion.
The quote you've given sounds to me like that guy just doesn't know which objects own which other objects, instead of having a proper ownership hierarchy where it's clearly defined how long everything lives.
As for boost::signals2, that's what a scoped_connection is for- i.e., you're doing it wrong.
The long and short is that there's nothing wrong with the tools in the Standard (except auto_ptr which is broken and bad and we have unique_ptr now). The problem is that you're not using them properly.

Related

Is it possible to implement a non-owning "slightly smart" pointer on top of standard weak pointers?

I've been thinking that while I understand the goals of std::observer_ptr I think it would be nice if there was at least an option for a similar pointer type that knows if what it points to has been deleted. For example, we could have something like the following
slightly_smart_ptr<Foo> p1(new Foo());
auto p2 = p1;
p1.erase(); // This deletes the foo referred to by p1.
if (p2.expired())
std::cout << "p2 is expired\n"; // this will fire
One way to achieve this with the current standard library is to make a shared_ptr to A in some scope that will exist for the lifetime of A, always refer to A by passing weak_ptrs around, and delete A when it is no longer needed by resetting the shared_ptr. The weak_ptrs here will have the basic semantics of observer_ptrs that know if A has been deleted. But there are problems with this approach: weak_ptrs must be locked, turning them into shared_ptrs to be used, which feels untidy, but more seriously a shared_ptr to A must exist somewhere, when all the user wants is a slightly smart pointer that does not own any content. The user agrees to manually destroy the content when it is time: no ownership is shared so it is a code smell for the user to create a shared_ptr in such a situation.
I however cannot think of a way in which the details of this implementation could be effectively hidden.
Also does such a pointer exist as a proposal or in a boost library or elsewhere?
The problem of such smart pointer is that it would be more error prone than std::unique_ptr, T* or std::weak_ptr.
When you want to know if a pointer has been deleted from elsewhere by it's unique owner, in reality you need shared ownership and std::weak_ptr.
You see, there is a reason why you need to "lock" a weak pointer before using it. It's because when you start using it, you gain ownership of the pointer. If you cannot lock your "observer pointer that knows if deleted or not", you cannot safely use it, since at any moment after verifying it's validity, it can be deleted.
Also, you have a deeper contradiction.
When you have a unique pointer, you know who is gonna delete it, and you know who is the owner.
If you have a program that checks for the validity of a pointer at runtime, then it's because your program doesn't know the state of the ownership of the resource.
If your program or parts of your program cannot know the state of the ownership of a resource and need to check if it had been deleted or not, then you need to ensure that it won't be deleted the next line while using it, since it can be deleted at any time, since you cannot know about its ownership status. Therefore you need to own the resource temporarily while using it. Therefore you need shared ownership to defer the ownership decision while executing the code.
If you have shared ownership, you don't need a observer pointer that knows if deleted or not.
Your pointer don't need to exist then.
So... you thought you need that pointer, it could be handy... what can you do?
You need to review your code. If there is a single ownership, why do you need to know the validity of the pointer. Why cannot you simply ask the owner?
If the owner don't exist, maybe your code that want to do the check should not be valid when the owner is deleted. Maybe your structure that want to do the check should die at the same time as the owner.
If your unique owner dies at an unpredictable moment (for example, your unique owner is held by a shared owner) then maybe your structure should check the validity of the shared owner instead.
Maybe your code calling the function that want to check if its pointer is still valid should simply not call it when there owner is dead.
...
And so on.
There is so many ways to solve that, but needing a weak pointer on a unique owner usually shows a flaw in the program or a problem in the reasoning of the lifetime of the objects in your program.
Not feasible in general.
The entire purpose of the extant smart pointers is to keep track of object lifetime and ownership in a way that simply isn't possible in general with raw pointers, unless you hooked into the allocator and had some convoluted relationship between this allocator and any handles pertaining to the allocated object.
The benefits you are describing are the benefits that come neatly from using said extant smart pointers. shared_ptr and weak_ptr are perfect here.
There's no problem with locking (you want this) and there's no problem with there having to be a shared_ptr somewhere, because surely someone somewhere does own that data. If they don't, your design has much bigger problems and you're trying to hack around those problems with a similarly broken smart pointer concept that'll never exist in the standard.

Leaving "zombie" flag upon object destruction

I want to explicitly destroy an object (call the destructor on it and all its fields), but it may happen that I still hold some pointers to the object in question. Thus, I don't want to yet free the memory; instead I would like to leave a sort of a flag "I am a destroyed object".
I came with an idea of the following approach:
class BaseClass { //all objects in question derive from this class
public:
BaseClass() : destroyed(false) {}
virtual ~BaseClass() {}
private:
bool destroyed;
public:
bool isDestroyed() { return destroyed; }
void destroy() {
this->~BaseClass(); //this will call the virtual destructor of a derivative class
new(this) BaseClass();
destroyed=true;
}
};
When destroy is called, I basically destroy the whatever object I had (perhaps a derivative one) and create a new "zombie" one in that very same place. As a result I hope to achieve:
Any other pointer ptr previously pointing to this object can still call ptr->isDestroyed() to verify its existence.
I am aware that if I don't check the flag of the zombie and try to access fields belonging to any derived object, bad things may happen
I am aware that the zombie object still consumes as much memory as the destroyed object (as it may be a derivative of BaseClass)
I still have to free memory of the destroyed object. I hope however, that calling delete is still correct?
Questions:
Are there any other problems which I should consider when using the above pattern?
Will calling delete on the zombie object correctly free whole memory consumed by the previous (normal) object?
While I appreciate your input on how to do it differently, and I may be inclined to do it your way - I would still like to understand all the risks that the above code poses.
You got some nasty comments to your question. Now I don't think they are deserved although there may be better ways to do what you want. I understand where you are coming from but actually you are using the destructor the same way you would use the reset function you refuse to write. Actually you gain nothing from calling a destructor since calling a distructor has nothing to do with actually deleting or resetting anything unless you actually write the code to do it within the destructor.
As to your question about the placement new:
As you may know already the placement new doesn't allocate any memory so calling it will just create the object in the same place. I understand that is exactly what you want but it's just not ncessary. Since you don't call delete on your object just destroy, you can set destroyed to true without initializing the class.
To sum it up:
If you use the destructor as a regular virtual function you gain nothing. Don't do it since you can get into trouble if a destructor is called twice
A call to a placement new will not allocate memory and just perform needless initialization. You can just set destroyed to true.
To do what you want to do correctly and gain the benefits of destructors, you should overload the new and delete operators of your classes and use the normal destruction mechanism. You can then opt not to release the memory but mark it as invalid or maybe release most of the memory but leave the pointer pointing to some flags.
EDIT
Following the comments I decided to sum up all the risks I see and the risks that others have pointed out:
Accessing invalid pointer in a multi-threaded environment: Using your method a class may be accessed after the destructor has run but before the destroyed flag is set (As to your question in one of the comments - shared_ptr is for most purposes thread safe)
Relaying on a behavior you don't totally control: Your method relies on the way destructors auto call the destructors of other members which are not dynamically allocated: This means that you still have to release dynamically allocates memory specifically, You have no control on how exactly this is implemented, You have no control on the order in which other destructors are called.
Relaying on a behavior you don't totally control (Point 2): You are relaying on the way a compiler implements the part of the destructor which calls other destructors you have no way in telling whether your code will be portable or even how will it handle calling it twice.
Destructors may be called twice: Depending on your implementation this may cause memory leaks or heap corruption unless you guard against releasing the same memory twice. You claim you guard against that case by calling the placement new - However in a multi-threading environment this is not guaranteed further more you assume that all memory allocations are done by the default constructor - depending on your specific implementation this may or may not be true.
You are going against the better judgment of everyone that answered your question or commented on it - You may be onto something genius but most probably you are just shooting yourself in the leg by limiting your implementation to a small subset of situations where it will work correctly. It is like when you use the wrong screwdriver you will eventually end up damaging the screw. In the same way using a language construct in a way it was not intended to be used may end up with a buggy program - Destructors are intended to be called from delete and from the code generated by the compiler to clear the stack. Using it directly is not wise.
And I repeat my suggestion - overload delete and new for what you want
There is a suggestion of using smart pointers. In fact - I am doing that, but my references are circular. I could use some fully-fledged garbage collectors, but since I know myself where (and when!) circle chains can be broken, I want to take advantage of that myself.
Then you can explicitly null-ify (reset if you are using shared_ptr) one of the circular smart pointers and break the cycle.
Alternatively, if you know where the cycles will be in advance, you should also be able to avoid them in advance using weak_ptr in place of some of the shared_ptrs.
--- EDIT ---
If an object referenced by weak pointers only would merely get flagged as "invalid" and release control over all its contained pointers (is this sentence clear?), I would be happy.
Then weak_ptr::expired should make you happy :)
As with everyone else, I recommend you should just use weak_ptr. But you asked why your approach doesn't work as well. There are some issue of elegant implementation and separation of concerns that your code walks all over, but I won't argue those. Instead, I'll just point out that your code is horribly not thread-safe.
Consider the following execution sequence of two threads of control:
// Thread One
if ( ! ptr -> isDestroyed() ) { // Step One
// ... interruption ...
ptr -> something(); // Step Three
And the other:
// Thread Two
ptr -> destroy(); // Step Two
By the time step 3 comes around, the pointer is no longer valid. Now it's possible to fix this by implementing lock() or similar, but now you've incurred the possibility of defects about not releasing locks. The reason that everyone is recommending weak_ptr is that this whole class of problems has been worked out both in the interface of the class and its implementations.
One issue remains. You seem to want a facility where you can kill an object at will. This is the tantamount to requiring that the only pointers to an object are weak ones, that no strong ones are present that would break when the object was manually deleted. (I'll stipulate that this isn't a bad idea, though I must say I don't know why it's not in your case.) You can get this by building on top of weak_ptr and shared_ptr. These classes are generic, so if you want to disallow shared_ptr access to BaseClass, then you can write a specialization for shared_ptr<BaseClass> that behaves differently. Hide one instance of shared_ptr<BaseClass> to prevent deletion and provide such pointers through a factory method under your control.
In this model the semantics of destroy() need attention. The first choice is whether you want synchronous or asynchronous operation. A synchronous destroy() would block until all external pointers are released and not allow the issuing of new ones. (I'll assume that copy constructors are already disabled on the pointer.) There are two kinds of asynchronous destroy(). The simpler of the two fails if there still exist external references. Calling unique() on the hidden shared_ptr() makes this an easy implementation. The more complicated one acts like an asynchronous I/O call, scheduling the destruction to happen at some point in the future, presumably as soon as all external references are gone. This function might be called mark_for_death() to reflect the semantics, since the object might or might not be destroyed at return time.
I would consider using one appropriate of the smart pointer patterns instead. Behavior of accessing a deleted object is still undefined and a 'zombie' flag won't really help. The memory that was associated with the object instance that was deleted could be immediately occupied by any other object created, thus accessing the zombie flag isn't an information you can trust.
IMHO the placement new operator
new(this) BaseClass();
used in your destroy() method won't really help. Depends a bit how this method is intended to be used. Instead of deleting derived objects or inside destructors of deleted objects. In the latter case the memory will be freed anyway.
UPDATE:
According to your edit, wouldn't it be better to use the shared pointer/weak pointer idiom to solve the occurrence of circular references. I would consider these as a design flaw otherwise.

A different kind of shared ownership

The shared_ptr in C++ comes to solve a problem, multiple deletes when multiple objects take ownership of an object. It does so by making only the last delete happen.
There is another flavor to that pointer is when an object wants ownership but doesn't want to delay a delete so it takes a weak pointer which notifies him when its deleted to prevent problems.
There is another way of doing this. Instead of making only the last delete happen, make only the first delete happen and the rest of the objects should be notified that it happened just like weak pointer does.
This is useful for object like a connection, that if one end releases it, it should be destroyed while the other end knows about this.
Is there anything like this in C++ or Boost?
This pattern could be modeled with a single shared, mutexed shared_ptr used only to create and destroy the object and a weak_ptr for each client/endpoint, used for access.
Note that such a scheme would cause excessive locking and might not give the semantics you want. You would need to lock the weak_ptr during use, which touches the shared_ptr internal mutex. When one side destroys the master shared_ptr instance, the object persists while any read operations finish.
The more conventional solution would be to transmit a hang-up message over the channel itself.
There are several types of notifications:
synchronous
asynchronous
on-demand (not really a notification)
Depending on what you really want, the implementation can vary a lot.
The latter (on-demand) is already available through the typical shared_ptr/weak_ptr dichotomy: when accessing the object through the weak_ptr, you'll know if it has been deleted meanwhile.
The other two can be implemented through an Observer pattern on top of a traditional shared_ptr, however they have complexity and performance consequences, so I would make sure that the need is real before using them.

shared_ptr, subscription, destructor

I'm using Boost/shared_ptr pointers throughout my application. When the last reference to an object is released, shared_ptr will delete the object for me. The objects in the application subscribes to events in a central location of the application, similar to the observer/subscriber pattern.
In the object destructors, the object will unsubscribe itself from the list of subscriptions. The list of subscriptions is essentially just a list<weak_ptr<MyObject> >. What I want to do is something similar to this:
Type::~Type()
{
Subscriptions::Instance()->Remove(shared_from_this());
}
My problem here is that shared_from_this cannot be called in destructors so the above code will throw an exception.
In my old implementation, the subscription list was just a list of pointers and then it worked. But I want to use weak_ptr references instead to reduce the risk of me screwing up memory by manual memory management.
Since I rely on shared_ptr to do object deletion, there's no single place in my code where I can logically place a call to Unsubscribe.
Any ideas on what to do in this situation?
You can destroy the objects via Subscription instance, then it'll automatically remove the pointers.
You can forget about removing them from subscriptions -- the weak_ptr's wont be able to be locked anyway, then you can remove them.
You can assign an unique ID to every object and then remove via the unique ID not the shared_ptr
You can pass a normal pointer to Remove instead of a shared one -- it will serve as an "ID".
My problem here is that shared_from_this cannot be called in
destructors so the above code will throw an exception.
It will throw an exception because it's expired, by definition, in a destructor.
So what do you want anyway? An "expired" shared pointer? Just create an empty shared pointer.
Or an expired weak pointer?
Maybe if you notice that the "problem" isn't shared_from_this throwing (it's a symptom) but all owners being inherently already reset or destroyed at that point and the weak pointers being expired and equivalent to an empty default created weak pointer (*), so you just should pass a default initialized weak pointer.
Also Subscriptions::Instance()->Remove(weak_OR_owning_pointer) makes no sense either way (with either weak or owning pointer) as you can't compare a weak pointer to anything, you can only try to lock it (and then do a comparison).
So you can just remove expired weak pointers. The arguments of Remove is useless.
(*) either that OR you have a very serious double bug of double ownership of the object being destroyed!

C++ and Smart Pointers - how would smart pointers help in this situation?

Much to my shame, I haven't had the chance to use smart pointers in actual development (the supervisior deems it too 'complex' and a waste of time). However, I planned to use them for my own stuff...
I have situations regarding de-initing a module after they are done, or when new data is loaded in. As I am using pointers, I find my code littered with check for null such as this...
// TODO: Reset all opened windows
// Deinit track result player
if (trackResultPlayer_)
trackResultPlayer_->reset();
// disconnect track result player
disconnect(trackResultPlayer_);
disconnect(trackResultAnimator_);
}
if (videoPlayerWindow_)
{
videoPlayerWindow_->reset();
// Disconnect the video player window from source movie data
disconnect(videoPlayerWindow_);
}
// Disconnect this module from its children as they would be connected again
disconnect(this);
If I am to use smart pointers, instead of raw pointers, how could this problem be alleviated?
Make each of your classes implement a destructor which performs all the cleanup/deinitialization you need for that class.
Create an instance of the class, and wrap it in a boost::shared_ptr.
Then pass copies of that to every function which needs access to the instance.
And the smart pointer will ensure that once the object is no longer used (when all the shared pointers have been destroyed), the object they point to is destroyed. its destructor is run, and all the cleanup is executed.
As always in C++, use RAII whenever possible.
Whenever you have code like x.reset() or disconnect(x), the first thing you should do is ask yourself "doesn't this belong in a destructor?"
Further, whenever you use x->y() you should ask yourself:
Why is this a pointer? Couldn't I make do with a single instance allocated on the stack, and perhaps a few references to it?
If it has to be a pointer, why isn't it a smart pointer?
Smart pointer are primarily an instrument to manage the memory being pointed to. They are not meant as something, which would free you from the burden of NULL value checking...
In you example code, I don't see much potential for smart pointers reducing the code complexity, unless you move calls like videoPlayerWindow_->reset(), disconnect(videoPlayerWindow_) and such into the destructor of the class, videoPlayerWindow is an instance of.
Checks against NULL aren't a problem - and smart pointers don't meddle with that anyway.