shared_ptr, subscription, destructor - c++

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!

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.

Syntax for converting expired weak_ptr<T> to shared_ptr<T>

From what I've read, a shared_ptr<T> does not get de-allocated until both strong references AND weak references to it are dropped.
I understand a shared object to be considered expired when there are no more strong references to it. The standard lock() function of a weak_ptr<T> therefore fails in such a case because the object is considered 'expired'.
However, if the deleter of a shared pointer is overridden such that the managed object is not deleted, then it should be valid to generated shared_ptr<T> from a weak_ptr<T> - but I cannot find the right syntax to do this.
std::shared_ptr<int> s_ptr(new(42), D());
std::weak_ptr<int) w_ptr(s_ptr);
s_ptr.reset();
s_ptr = std::shared_ptr<int>(w_ptr, false);
EDIT
To clarify this a bit further, I'm trying to construct an object pool of re-usable shared_ptr<T>. The reason behind this is because every use of shared_ptr results in one or more heap memory allocations. So I've added a deleter to every shared_ptr<T> which stores a weak_ptr<T> reference such that then the deleter gets called it should be able to re-add itself to a pool of available shared_ptr<T> objects (with managed object intact). By keeping a weak_ptr<T> stored inside the shared_ptr<T>'s deleter, it therefore shouldn't stop the deleter from being called.
The end goal is to obtain a smart pointer that doesn't do consisant heap allocation - or at least only a small number.
From what I've read, a shared_ptr does not get de-allocated until both strong references AND weak references to it are dropped.
Wrong. a std::shared_ptr has two blocks - a control block that contains reference counts, etc, then another block for the actual data.
When the shared count goes to 0, the data block is (usually) deallocated. This is why it is illegal to make a std::shared_ptr from a expired std::weak_ptr.
On another note, why would you EVER want this functionality? It ruins the entire point of std::weak_ptr, which is to be able "store" a pointer to a object stored by std::shared_ptr without incrementing its reference count.
If you want to do that, then please just use a std::shared_ptr
If pooling control blocks is a good idea, the library implementation may already be doing it. In fact, the implementation of new itself may already be doing pooling to support similar memory usage patterns.
Furthermore, you can achieve what I think your goals are by using make_shared rather than invoking new and passing it into a shared_ptr constructor; one of the reasons for the existence of this helper function is that it can be written to use a single allocation to allocate both the control block and the new object you're creating at the same time.

Binding a callbacks to an expiring shared_ptr?

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.

Can I make a shared object pool using std::shared_ptr and weak_ptr without a custom destructor?

I want to have a pool of shared objects whose class name is Shader. I want a "client" to be able to request a Shader with certain parameters from the pool manager, and if there's one already in the pool the manager will return a pointer or reference to it, otherwise it creates a new Shader and adds it to the pool before returning its reference. Easy enough so far.
However, I also want the Shaders to be automatically deleted when all the clients have finished with them. Is this possible by implementing the pool as a container of std::weak_ptr and returning std::shared_ptr to the clients? Ie if I call weak_ptr::lock() multiple times on the same object are the shared_ptrs it returns linked to each other correctly, or does it return independent shared_ptrs leading to undefined behaviour? cpprefrence.com implies the latter, but they don't explictly point out the danger of that, and it seems to me that an opportunity was missed to make weak_ptr considerably more useful.
Calling weak_ptr::lock() multiple times is ok, the returned shared_ptr is configured properly, i.e. all shared_ptr-s having the common pointee are sharing the reference counter.
Note that lock() returns non-null pointer iff there is at least one shared_ptr pointing to the object. If there was none then the object would have been already destroyed. Hence lock() absolutely must implement sharing right otherwise it would break on every call.
Finally shared_ptr supports custom deleter functions, they may be useful to remove stale entries from the cache.
Is this possible by implementing the pool as a container of std::weak_ptr and returning std::shared_ptr to the clients?
Yes.
Ie if I call weak_ptr::lock() multiple times on the same object are
the shared_ptrs it returns linked to each other correctly, or does it
return independent shared_ptrs leading to undefined behaviour?
weak_ptr::lock() returns shared_ptr linked to other shared_ptrs to that object or empty shared_ptr when there are no other shared_ptrs (IOW weak_ptr::expired() is true).
cpprefrence.com implies the latter, but they don't explictly point out
the danger of that, and it seems to me that an opportunity was missed
to make weak_ptr considerably more useful.
I can not understand how you read that implication.

How do I prevent deletion of a pointer without using const?

I have a class that contains a vector of object pointers. I have a GetObject(..) function in that class that looks through the vector, finds the object desired, and returns a pointer to it. However, if the user of the class does a delete() on that returned pointer, my program will crash because the vector still has a pointer to that, now invalid, object. So, in my GetObject() class, I can return a const pointer, but that doesn't solve the problem because you can still delete the object. The object is mutable so I can't return a pointer to a const object. I suppose I could prevent deletion by returning a reference to the object but I have my function returning NULL if there is an error. I guess I can pass back the object reference via the parameters and then return and error number like this
//-1 on object on found. 0 for success. Object is passed back in
// the function parameter result.
int MyObject::GetObject(int object_id, Item& result)
Is this the best solution for such a situation?
The best way to solve this problem is to use a shared-ownership smart pointer like shared_ptr, which you can find in Boost, C++ TR1, and C++0x.
A smart pointer is a container that manages the lifetime of your dynamically allocated object for you. It takes responsibility for deleteing the object when you are done using it.
With a shared ownership smart pointer, you can have multiple smart pointers that all share ownership of the dynamically allocated object. A reference count is kept that keeps track of how many smart pointers have ownership of the object, and when the last owning smart pointer is destroyed, the dynamically allocated object is deleted.
It is extremely difficult to manage resources manually in C++, and it's very easy to write code that looks correct and works right most of the time but that is still not correct. By using smart pointers and other resource-owning containers (like the standard library containers), you no longer have to manage resource manually. It is significantly easier to write correct code when all of your resource management is automatic.
Automatic resource management in C++ is accomplished using a design pattern called Resource Acquisition is Initialization (RAII), which is arguably the most important design pattern you as a C++ programmer should become familiar with.
Anybody in your code could also try to de-reference NULL. You going to stop them doing that too? If your container owns the object, and you make this clear (returning a raw pointer is usually pretty clear or mention in docs), then anyone who deletes it, the result is their own fault. The only way that you could guarantee the prevention of the deletion of the object is to prevent the user from ever gaining a native reference or pointer - in which case they just can't access the object.
Who are clients of your class? If they are not your mortal enemies you could just ask them nicely not to delete the object. Otherwise, there will always be a way for "them" to mess you up.
Okay, one possible solution is to make destructor private. That will prevent everyone from deleting the object. But then the object has to delete itself (delete this) somehow, maybe through some function called DeletObjectButDontBlameMeIfAppCrashes. If the owner is some other class then you can set the destructor to protected and owner class as friend of this class.
You should return a reference to the object. There are two ways to handle the case when there is no object found.
First, you can use the Null Object Pattern in order to implement a special value for that case. That might not make sense for your case though.
The other way is to split it up into two methods, one which can be used to check if an appropriate element exists, and one to retrieve it.
Many STL-containers or algorithms implement both of these, either by returned a past-the-end iterator, or by having empty() returns false as a prerequisite of calling a method like front or back.
If you can use the boost libraries, smart pointers can be used to ensure that pointers stay valid. Essentially, each reference to a smart pointer increases its "use count" by 1. When the reset function is called on a reference, the reference goes away and the use counter decrements. As long as some object is still holding on to a smart pointer, the reference will be valid. Note that the other classes will be able to change what its pointing to, but can't delete it.
(My description deals mainly with smart pointers specifically - the different types of pointers vary a little, but the general idea remains the same).