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.
Related
Assuming I know the stack frame will outlive all the copies of the shared_ptr, is there any way to create a shared_ptr to a stack object such that the reference counter is also on the stack so that there's no dynamic allocation at any point?
e.g.
SomeObject anObject;
std::shared_ptr::ref_counter refCounter; // Does this exist?
std::shared_ptr<SomeObject>(&anObject, &refCounter, [](SomeObject* obj){
obj->DoSomething();
});
The goal here being to use shared_ptr for its reference counting rather than as a smart pointer.
EDIT: I'm gonna add some more explanation to make the reasons for doing this more clear.
I'm trying to create a token that calls a function when it and all its copies are destroyed for a threading library I'm writing. Each token is essentially just a wrapper for a smart pointer to a persistent object that holds the function and calls it in its destructor. Copying the token copies the wrapper (and thus the smart pointer), but not the persistent object.
Given that these tokens may be passed to many different threads the persistent object usually needs to be on the heap, but some of the time I can actually guarantee that a particular stack frame will outlive all the copies of any tokens it creates. In those situations the persistent part of the token can be created on the stack, forgoing any expensive heap allocation.
So in some situations the smart pointer does need to actually own the object it's pointing to, but in others it doesn't.
There is no way to manage a stack allocated object with a shared pointer.
However, there should not be any need for it either. In place of the shared pointer, you can use a bare pointer or perhaps a reference. Since you know that the referenced object will outlive all users, it is safe.
I'm trying to create a token that calls a function when it and all its copies are destroyed
For that, you don't want to use a shared pointer. You should just implement your own reference counter.
you can do this but it would not be a good choice*.
SomeObject anObject;
std::shared_ptr<SomeObject>(&anObject, [](auto x){}});
coliru example
*this does not use most of the functionality of shared_ptr and is a waste, and the count can be recorded in many other ways include implement you own counting class.
I really see no reason prevent dynamic allocation. Even if you can't use heap, the dynamic allocation can happens fully on stack.
If I understand correctly, a weak_ptr doesn't increment the reference count of the managed object, therefore it doesn't represent ownership. It simply lets you access an object, the lifetime of which is managed by someone else.
So I don't really see why a weak_ptr can't be constructed from a unique_ptr, but only a shared_ptr.
Can someone briefly explain this?
If you think about it, a weak_ptr must refer to something other than the object itself. That's because the object can cease to exist (when there are no more strong pointers to it) and the weak_ptr still has to refer to something that contains the information that the object no longer exists.
With a shared_ptr, that something is the thing that contains the reference count. But with a unique_ptr, there is no reference count, so there is no thing that contains the reference count, thus nothing to continue to exist when the object is gone. So there's nothing for a weak_ptr to refer to.
There would also be no sane way to use such a weak_ptr. To use it, you'd have to have some way to guarantee that the object wasn't destroyed while you were using it. That's easy with a shared_ptr -- that's what a shared_ptr does. But how do you do that with a unique_ptr? You obviously can't have two of them, and something else must already own the object or it would have been destroyed since your pointer is weak.
std::weak_ptr can't be used unless you convert it to std::shared_ptr by the means of lock(). if the standard allowed what you suggest, that means that you need to convert std::weak_ptr to unique in order to use it, violating the uniqueness (or re-inventing std::shared_ptr)
In order to illustrate, look at the two pieces of code:
std::shared_ptr<int> shared = std::make_shared<int>(10);
std::weak_ptr<int> weak(shared);
{
*(weak.lock()) = 20; //OK, the temporary shared_ptr will be destroyed but the pointee-integer still has shared to keep it alive
}
Now with your suggestion:
std::unique_ptr<int> unique = std::make_unique<int>(10);
std::weak_ptr<int> weak(unique);
{
*(weak.lock()) = 20; //not OK. the temporary unique_ptr will be destroyed but unique still points at it!
}
That has been said, you may suggest that there is only one unique_ptr, and you still can dereference weak_ptr (without creating another unique_ptr) then there is no problem. But then what is the difference between unique_ptr and shared_ptr with one reference? or moreover, what is the difference between a regular unique_ptr and C-pointers an get by using get?
weak_ptr is not for "general nonowning resources", it has a very specific job - The main goal of weak_ptr is to prevent circular pointing of shared_ptr which will make a memory leak. Anything else needs to be done with plain unique_ptr and shared_ptr.
A shared_ptr basically has two parts:
the pointed-to object
the reference count object
Once the reference count drops to zero the object (#1) is deleted.
The weak_ptr needs to be able to know if the object (#1) still exists. In order to do this, it has to be able to see the reference count object (#2), if it's not zero it can create a shared_ptr for the object (by incrementing the reference count). If the count is zero it will return an empty shared_ptr.
Consider the question of when can the reference count object (#2) be deleted? We must wait until no shared_ptr OR weak_ptr object refer to it. For this purpose the reference count object holds two reference counts, a strong ref and a weak ref. The reference count object will only be deleted when both these counts are zero. This means that part of the memory can only be freed after all the weak references are gone (this implies a hidden disadvantage with make_shared).
tl;dr; weak_ptr depends on a weak reference count which is part of shared_ptr, there cannot be a weak_ptr without a shared_ptr.
Conceptually, there is nothing preventing an implementation where a weak_ptr only provides access and a unique_ptr controls the lifetime. However, there are problems with that:
unique_ptr doesn't use reference counting to begin with. Adding the management structure for managing the weak references would be possible, but require an additional dynamic allocation. Since unique_ptr is supposed to avoid any(!) runtime overhead over a raw pointer, that overhead is not acceptable.
In order to use the object referenced by a weak_ptr, you need to extract a "real" reference from it, which will first validate that the pointer is not expired first and then give you this real reference (a shared_ptr in this case). This means that you suddenly have a second reference to an object that is supposed to be uniquely owned, which is a recipe for errors. This can't be fixed by returning a mixed half-strong pointer that only temporarily delays possible destruction of the pointee, because you could just as well store that one, too, defeating the idea behind unique_ptr.
Just wondering, what problem are you trying to solve using a weak_ptr here?
Looks like everyone is writing here about std::weak_ptr but not about weak poiner concept which I believe is what the author is asking for
I think that no one mentioned why standard library is not providing weak_ptr for unique_ptr. Weak pointer CONCEPT doesn't disclaims unique_ptr usage. Weak pointer is only an information if the object has been already deleted so it's not a magic but very simple generalized observer pattern.
It's because of threadsafety and consistency with shared_ptr.
You just simply can't guarantee that your weak_ptr (created from unique_ptr existing on other thread) will be not destroyed during calling method on pointed object.
It's because weak_ptr needs to be consistent with std::shared_ptr which guarantee threadsafety. You can implement weak_ptr which works correctly with unique_ptr but only on the same thread - lock method will be unnecessary in this case. You can check chromium sources for base::WeakPtr and base::WeakPtrFactory - you can use it freely with unique_ptr.
Chromium weak pointer code is most probably based on last member destruction - you need to add factory as a last member and after that I believe that WeakPtr is informed abut object deleteion (I'm not 100% sure) - so it doesn't looks so hard to implement.
Overall using unique_ptr with weak pointer concept is OK IMHO.
No-one has mentioned the performance aspect of the problem yet, so let me throw my $0.02 in.
weak_ptr must somehow know when the corresponding shared_ptrs have all gone out of scope and the pointed object has been deallocated and destroyed. This means that shared_ptrs need to communicate the destruction towards each weak_ptr to the same object somehow. This has a certain cost – for example, a global hash table needs to be updated, where weak_ptr gets the address from (or nullptr if the object is destroyed).
This also involves locking in a multi-threaded environment, so it can potentially be too slow for some tasks.
However, the goal of unique_ptr is to provide a zero-cost RAII-style abstraction class. Hence, it should not incur any other cost than that of deleteing (or delete[]ing) the dynamically allocated object. The delay imposed by doing a locked or otherwise guarded hash table access, for example, may be comparable to the cost of deallocation, however, which is not desirable in the case of unique_ptr.
It may be useful to distinguish reasons for preferring a unique_ptr over a shared_ptr.
Performance One obvious reason is computational-time and memory use. As currently defined, shared_ptr objects typically need something like a reference-count value, which takes space and also must be actively maintained. unique_ptr objects don't.
Semantics With a unique_ptr, you as the programmer have a pretty good idea when the pointed-to object is going to be destroyed: when the unique_ptr is destroyed or when one of its modifying methods is called. And so on large or unfamiliar code bases, using unique_ptr statically conveys (and enforces) some information about the program's runtime behavior that might not be obvious.
The comments above have generally focused on the performance-based reasons that it would be undesirable for weak_ptr objects to be tied to unique_ptr objects. But one might wonder if the semantics-based argument is sufficient reason for some future version of the STL to support the use-case implied by the original question.
After many years of c++ programing works, i finally realized that the correct way in c++ world is not to use shared_ptr/weak_ptr for ever. We have spent so many time to fix the bugs caused by the unclear ownership of share_ptr.
The solution is to use unque_ptr and some weak pointer for unique_ptr instead, just as what's expected in this topic.
cpp standard library has no weak pointer for unique_ptr, so i create a very simple, but useful libary here --
https://github.com/xhawk18/noshared_ptr
It has two new smart pointers,
noshared_ptr<T>, a new kind of unique_ptr
noweak_ptr<T>, the weak pointer for noshare_ptr<T>
I demonstrated the problem to myself with a MWE implementing weak_ptr on single objects. (I implement it on X here, but X can be anything that can tell us when it dies, such as a unique_ptr with a custom deleter).
The ultimate problem however is that at some point we need reference counting on the weak pointers themselves, because while X is not shared, the weak pointers are shared. This takes us full circle back to using shared_ptr again.
Perhaps the only advantage of doing this is that the intent of single ownership is clearer and cannot be violated, however, as Stroustrup suggests and is quoted this answer, this can be hinted at with the using statement.
#include <iostream>
#include <memory>
template<typename T>
struct ControlBlock
{
T* Target;
explicit ControlBlock(T* target) : Target(target) {}
};
template<typename T>
struct WeakReference
{
std::shared_ptr<ControlBlock<T>> ControlBlock;
T* Get() { return ControlBlock ? ControlBlock->Target : nullptr; }
};
template<typename T>
struct WeakReferenceRoot
{
WeakReference<T> _weakRef;
WeakReferenceRoot(T* target) : _weakRef{std::make_shared<ControlBlock<T>>(target)} { }
const WeakReference<T>& GetReference() { return _weakRef; }
~WeakReferenceRoot() { _weakRef.ControlBlock->Target = nullptr; }
};
struct Customer
{
WeakReferenceRoot<Customer> Weak{this};
};
int main() {
WeakReference<Customer> someRef;
std::cout << "BEFORE SCOPE - WEAK REFERENCE IS " << someRef.Get() << "\n";
{
Customer obj{};
someRef = obj.Weak.GetReference();
std::cout << "IN SCOPE - WEAK REFERENCE IS " << someRef.Get() << "\n";
}
std::cout << "OUT OF SCOPE - WEAK REFERENCE IS " << someRef.Get() << "\n";
return 0;
}
Sadly as with many cases - cause the C++ committee just didn't care and dismissed such usecases.
How it is:
weak_ptr was specified in terms of shared-pointer, precluding any attempts at making it a more broadly useful smart-pointer. In C++ conceptually a weak-ptr is a non-owning pointer that MUST be converted to a shared_ptr to access the underlying object. And as a unique_ptr does not support any sort of reference-counting (as it is the unique owner by definition) converting a weak_ptr to a pointer with any sort of ownership is not allowed.
It is sadly a bit too late to get good well-named smart-pointers that offer a bit more generality.
But you can create something like that:
To make it safe you would need your own deleter (unique_ptr has the deleter in the type), and a new non-owning unique_ptr_observer that changes the deleter. When creating an observer it would register a cleanup-handler as the deleter. That way you can have a unique_ptr_observer that can check if the Threadsafety would still be a problem as you would need either a locking-mechanism, create copies for readout, or some other way to prevent the pointer from getting deleted while you are actively looking at it.
(it is so annoying that the deleter is part of the type.......)
I'm somewhat used to the concept of refcounting through COM and I'm somewhat new to shared_ptr. There are several nice properties with CComPtr that I don't find in shared_ptr, and I'm wondering what are the pattern that prevent missuse of shared_ptr.
The AddRef/Release pattern guarantees there is only one refcount per object (the refcount is stored on the object itself), so it's safe, when you have a random pointer to create a CComPtr around it. On the other hand, shared_ptr has a separate refcount pointer, so it's unsafe to create a new shared_ptr on an object (why does the standard provide a constructor that takes a T* on shared_ptr if it's so unsafe to do?). That seems such a big limitation that I don't understand how one can use shared_ptrs...
A bit corner case: something that I've done in the past with AddRef/Release: I want a container of "weak references" to IFoos (for example a map from URL to IConnection or something). With weak_ptr, I can do that but my collection won't "clean itself up", I'll have expired pointers in it. With Release, I can implement my own weak pointer (a bit of work) that actually cleans up the collection. Is there an alternative with shared/weak_ptr?
Intuitively, there is a performance penalty in doing two memory allocations to create an object (one for the refcount, one for the object) compared to the IUnknown world where you do only one. There is also a locality penalty when accessing the object (assuming that an AddRef is frequently followed by reading the content of the object, which seems likely). Has the cost of both approaches been compared?
why does the standard provide a constructor that takes a T* on shared_ptr if it's so unsafe to do?
Because it's the only way to have shared_ptrs without being intrusive. You can use a shared_ptr on anything. I've even used them on objects from C interfaces, via the use of a deleter object. Things like a cairo_t* and so forth. That way, I never have to free anything ever again.
You can't do that with CComPtr; it only works for IUnknown-style objects.
Also, there is std::make_shared, which creates a shared_ptr directly from an object type and the argument to the constructor. So you never even see the pointer (and it usually allocates the object and its ref-count in one allocation instead of two).
The proper C++ idiom with shared_ptr is very simple: always use make_shared or alloc_shared. If you can't use them, then the proper idiom is to only use the direct naked pointer constructor in tandem with new: shared_ptr<T> pVal{new T{...}}; (or the appropriate function that creates the pointer). Never use it on pointers that you don't know the origin of.
Is there an alternative with shared/weak_ptr?
No, but there are tools to make one if you so desire. Besides the obvious method (run through your collection periodically and remove dead weak_ptrs), you can associate a deleter with the shared_ptr that will (in addition to deleting the pointer) call whatever cleanup function to remove those weak_ptrs.
Intuitively, there is a performance penalty in doing two memory allocations to create an object
See make_shared, above.
There is also a locality penalty when accessing the object (assuming that an AddRef is frequently followed by reading the content of the object, which seems likely).
You don't have to copy the shared_ptr to talk to its contents, nor do you have to bump the reference count to do so.
Now, let's talk about some of the things CComPtr can't do. It's intrusive. It can't be used with arbitrary allocators or deleters (obviously not as important when it's intrusive). It can't do pointer aliasing, where you have a shared_ptr to a member of an object, but the actual reference count is for the object it is a member of. That's a very useful thing to be able to do.
Oh yeah, it's not cross-platform. It's not bound to COM, IUnknown, and all of that overhead.
I can't think of any situation where
std::shared_ptr<Object> obj(new Object("foo", 1));
would be preferred to
auto obj = std::make_shared<Object>("foo", 1);
The latter always results in better locality and reduces memory fragmentation. Is there any situation, where you would prefer (or be forced) to use the first form, except interfacing with code returning raw pointers?
The latter always results in better locality and reduces memory fragmentation.
Not always. An implementation is encouraged to use a single allocation for the reference counted object and the reference count, but it is not required to do so.
Why might you not want to use std::make_shared? Consider the case where you have a large dynamically allocated object that you want owned by std::shared_ptr and you know that there will be weak references to this object that are likely to outlive the strong references to the object (perhaps there are many weak references and only one or two short-lived strong references).
In this case, std::make_shared would be a poor choice, assuming it allocates a single block that owns both the object and the reference count: the allocated block (which is large, remember) cannot be destroyed until there are no strong or weak references left to the object.
If you were to dynamically allocate the object yourself and pass the pointer to the std::shared_ptr constructor, the memory occupied by the object could be released as soon as there are no strong references remaining, even if there are still weak references.
If you are constructing an object that will have multiple entities sharing in the lifetime of the object, then yes, you want to prefer to use std::make_shared where possible. Some places it might not be possible is if you obtain the pointer from someone else; for example, a factory might return a raw pointer or a std::unique_ptr that you would like to store in a shared_ptr, thus preventing use of make_shared.
The question in the title is a bit different; there are plenty of reasons you might not want to use shared_ptr for your objects at all. You should only use shared_ptr if the lifetime is actually shared by multiple objects. Otherwise, prefer stack allocating the object or using unique_ptr.
Modern IDEs have "Find usages" feature. If you use std::make_shared to construct the object, when you search for the places where the constructor of that object is called, IDE won't show up the places where std::make_shared is used.
I make a lot of use of boost::scoped_ptr in my code and it is great but I'm currently working with software that uses shared_ptr all over the place and I'm wondering if I'm missing something.
AFAIK a shared_ptr is only useful if different threads are going to be accessing the same data and you don't know what order the threads are going to finish (with the shared_ptr ensuring that the object exists until the last thread has finished with it).
Are there other use cases?
Threads are irrelevant here. What's relevant is whether it's easy to specify a point at which the object is no longer of use.
Suppose several different objects want to use the same object. It might be a pack of data, or for input/output, or some geometric object, or whatever. You want the shared object to be deleted after all of the using objects are deleted, and not a clock cycle before. Rather than figure out which owning object is going to have the longest lifespan (and that can change if you change the program, or perhaps through user interaction), you can use a shared_ptr to force this behavior.
It doesn't matter whether the using objects are in the same or different threads. Objects can have unpredictable lifetimes even if they're all in the same thread.
AFAIK a shared_ptr is only useful if
different threads are going to be
accessing the same data
Well, it's for situations where multiple owners own the same object pointed to by the smart pointer. They may access the smart pointers from different threads, and shared_ptr is usable in that area too, but that's not the main point. If the last owner loses its reference to the object pointed to, the shared_ptr mechanism deletes the object.
You can use a scoped_ptr if all you want to have is a pointer that is deleted when the scope it's created in is left (either by exceptions, by a goto to a place outside, or by normal control flow or some other mechanism). If you use it like that, there is no need to change to shared_ptr.
The difference between scoped_ptr and shared_ptr (and auto_ptr) is mainly copy semantics.
scoped_ptr is for "Resource Allocation Is Initialization" and is not copyable (it cannot be shared with other instances and ownership cannot be transferred)
shared_ptr is for automatic reclamation of memory when shared between multiple parties
auto_ptr is copyable (and transfers ownership when assigned)
Another important difference between shared_ptr and scoped_ptr is that only shared_ptr work with weak_ptr. Weak pointers are used to break cycles of shared pointers, thereby avoiding memory leaks, but weak_ptr can be used for more than that.
Shared and weak pointers may be used to express the difference between owning and non-owning references. Unambiguous ownership of data leads to a cleaner design, so when possible data objects should be owned by one other object through a shared_ptr. All other long-lived references to data objects should be weak pointers, expressing their non-ownership of the data. Each time any non-owning modules access the data, they need to convert the weak_ptr into a shared_ptr, at which point they may find that the data object no longer exists. However, while the non-owning modules access the data object, they hold it through transient shared_ptr, ensuring safe operation even if the owning object were to release the data.
As answered already, shared_ptr is about shared ownership. However, I would argue that shared ownership is generally a bad thing (exceptions exists, such as flyweight pattern) and it is better to identify an owner and put a scoped_ptr there.
A shared_ptr is a smart pointer type that does reference counting. If there's only one owner for the object (frequent case), then scoped_ptr is the right solution. If the object can be shared among multiple parts of the code, then shared_ptr won't let the object be destructed until all references to it have been released.