Use for applying weak_ptr to contents of unique_ptr - c++

I'm trying to understand the unique_ptr, shared_ptr, and weak_ptr that came in with c++11.
I've heard that weak_ptr's would be nice for things like caching, and breaking cycles, and so on. I've heard that they work well with shared_ptrs.
But in this regard, what's the difference between shared_ptrs and unique_ptrs? Why does weak_ptr only get to be used with one and not the other? Why wouldn't I want to have a weak reference to something owned by someone else?

A weak_ptr is technically a means to hang on to the reference counter of a set of shared_ptrs that manage some shared object. When the last shared_ptr is destroyed the object is destroyed, but its reference counter lives on as long as there are weak_ptrs to it. Thus via any still exising weak_ptr you can check whether the object still exists, or has been destroyed.
If it still exists then from the weak_ptr you can obtain a shared_ptr that lets you reference the object.
The main usage of this is to break cycles.
In particular, an object can contain a weak_ptr holding on to its own reference counter, which allows you to obtain a shared_ptr to the object from the object itself. That is, a shared_ptr that uses the same reference counter as other shared_ptrs to this object. Which is how enable_shared_from_this works.
unique_ptr doesn't have any reference counter, so it doesn't make sense to hang on to that non-existent reference counter.

The major point of a weak pointer is that you can try to make the pointer strong, that is owning:
auto strongPtr = weakPtr.lock();
if (strongPtr)
{
// still existed, now have another reference to the resource
}
else
{
// didn't still exist
}
Note the first path: making a weak pointer stronger requires we take ownership of the object.
This is why it doesn't make sense with unique_ptr: the only way to make the weak pointer strong is to take the resource from somewhere else, and for unique_ptr that would mean leaving that somewhere else with an unexpected null pointer. shared_ptr gets a pass because taking it really means sharing it.

I'm new to C++11 as well, so if someone knows better I would appreciate any corrections.
I think that there wouldn't be much of a reason to, otherwise, you'd use a shared_ptr since it would defeat the whole purpose of a unique_ptr. A unique_ptr has implied semantics that it has complete control over the object to which it points.

Related

what happens if I reset a unique_ptr with a shared_ptr pointing to it?

I would be surprised if this is not answered somewhere already. But I have not found it.
Anyway, as the question says I want to know what happens if I create a shared pointer from a unique pointer. I saw some suggestions from here:
// Factor that returns unique_ptr
std::unique_ptr<ModelObject_Impl> factory();
// Store a shared_ptr to that returned unique_ptr
auto shared = std::shared_ptr<ModelObject_Impl>(factory());
Which got me thinking if I did something similar - where I have an owning-object that has a function that returns some internal object by unique_ptr - and I make a shared_ptr out of it (perhaps as suggested in the link). Then later if that owning-object destroys / resets its internal object - then what happens to my shared_ptr to it?
I know this is not quite what the link is suggesting to do - but I am not quite sure if this is a "good practise" or "undefined behaviour" - as far as I can tell, this would result in a dangling shared_ptr...
where I have an owning-object that has a function that returns some internal object by unique_ptr - and I make a shared_ptr out of it (perhaps as suggested in the link). Then later if that owning-object
Stop. You have contradicted yourself. If object X owns object Y, and it returns a unique_ptr to Y, it no longer owns Y. That is what it means to return a unique_ptr to something.
If it returned a reference to a unique_ptr, well it doesn't matter because you either moved from it into your shared_ptr (in which case again, X no longer owns it), or you didn't, in which case you don't own it. Either way, ownership is unique.
To create a shared_ptr from a unique_ptr means that the shared_ptr claims ownership over the object. The unique_ptr no longer has it afterwards. That's why it takes an rvalue-reference to a unique_ptr; you have to move into the shared_ptr.

Is there any advantage to using a naked pointer rather than a weak_ptr?

Question: Are there any compelling reasons to use naked pointers for non-owning resources or should we be using weak_ptr?
CPP.reference states
std::weak_ptr models temporary ownership: when an object needs to be accessed only if it exists, and it may be deleted at any time by someone else
But then, in the accepted answer for Which kind of pointer do I use when? we have the statement:
Use dumb pointers (raw pointers) or references for non-owning references to resources and when you know that the resource will outlive the referencing object / scope. Prefer references and use raw pointers when you need either nullability or resettability.... If you want a non-owning reference to a resource, but you don't know if the resource will outlive the object that references it, pack the resource in a shared_ptr and use a weak_ptr.
This answer is followed by a lot of back-and-forth about the use of naked pointers, with no real resolution. I can't see any reason for using dumb pointers. Am I missing something?
A weak_ptr has a very specific purpose: to break shared_ptr cycles. As an example, std::enable_shared_from_this is based on letting an object contain a weak_ptr to itself. If it directly contained a shared_ptr then that would create a cycle, so instead it has a weak_ptr.
You use a weak_ptr where you would otherwise have had a shared_ptr. The weak_ptr has a higher cost because in addition to the costs of shared_ptr there is the object existence checking that produces a shared_ptr, or not. Also it's a more complex beast so that it's easier to use incorrectly.
I can't think of any way that weak_ptr has anything to do with “temporary ownership” (except that after checking of existence and using a produced shared_ptr, that's one temporary shared ownership, which is repeated again and again for each use). For example, std::enable_shared_from_this has nothing to do with temporary ownership. Ordinarily I would just ignore a source of such a claim, and advice others to ignore it, but cppreference.com is about the best we have in the way of a free online C++ reference. It's odd that it contains a nonsense statement. But, nothing's prefect, as I once remarked to Bjarne in clc++, whereupon he corrected my speling of “prefect”. Hm! Well.
I don't know of any advantage in using a raw pointer rather than a weak_ptr, where a weak_ptr is what's required. A raw pointer can't do a weak_ptr's job of holding on to a shared_ptr's control block, so it seems to me that the mere idea of replacing a weak_ptr with a raw pointer is nonsense. But then, the day one stops being surprised by learning things one could never have thought of, is the day one is dead, and so it may be the case that there is some obscure-to-me such use.
Also, there is no advantage in using a weak_ptr where a raw pointer is what's required. Rather, the weak_ptr introduces a relatively speaking enormous cost, of control block allocation and reference counting. So I can't think of any situation where it would make sense to replace raw pointers with weak_ptr, and I don't expect this to be a case where I learn otherwise.
a weak pointer actually has very little usage. A weak pointer is only useful, if you need it's lock function (transform the pointer into a shared pointer, to prevent garbage collection while you are operating on it). Non owning pointers best, if you just use raw pointer, because of the overhead shared and weak pointer have.

Why can't a weak_ptr be constructed from a unique_ptr?

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.......)

Can I get a raw pointer from boost's weak_ptr?

Is it possible to get a raw pointer from boost::weak_ptr? Boost's shared_ptr has get() method and "->" operator. Is there some rationale behind weak_ptr not having the same functionality?
A weak_ptr holds a non-owning reference, so the object to which it refers may not exist anymore. It would be inherently dangerous to use a raw pointer held by a weak_ptr.
The correct approach is to promote the weak_ptr to a shared_ptr using weak_ptr::lock() and get the pointer from that.
The Boost weak_ptr documentation explains why it would be unsafe to provide get() functionality as part of weak_ptr, and has examples of code that can cause problems.
This is an old question and the accepted answer is good, so I hesitate to post another answer, but one thing that seems missing is a good idiomatic usage example:
boost::weak_ptr<T> weak_example;
...
if (boost::shared_ptr<T> example = weak_example.lock())
{
// do something with example; it's safe to use example.get() to get the
// raw pointer, *only if* it's only used within this scope, not cached.
}
else
{
// do something sensible (often nothing) if the object's already destroyed
}
A key advantage of this idiom is that the strong pointer is scoped to the if-true block, which helps to prevent accidental use of a non-initialised reference, or keeping a strong reference around longer than it is actually required.
You first need to derive the shared_ptr from the weak_ptr before getting hold of the raw pointer.
You can call lock to get the shared_ptr, or the shared_ptr constructor:
boost::weak_ptr<int> example;
...
int* raw = boost::shared_ptr<int>(example).get();

Boost weak_ptr's in a multi-threaded program to implement a resource pool

I'm thinking of using boost::weak_ptr to implement a pool of objects such that they will get reaped when nobody is using one of the objects. My concern, though, is that it's a multi-threaded environment, and it seems there's a race condition between the last shared_ptr to an object going out of scope and a new shared_ptr being constructed from the weak_ptr. Normally, you'd protect such operations with lock or something; however, the whole point here is that you don't know when the shared_ptr might be going out of scope.
Am I misunderstanding something about boost::shared_ptr and boost::weak_ptr? If not, does anybody have any good suggestions on what to do?
Thanks.
Andrew
To use a weak_ptr, you normally have to grab a strong reference by constructing a shared_ptr with it. This last step is atomic: you either get a strong reference back, or you get a bad_weak_ptr exception thrown. (Alternatively, call lock() on the weak_ptr, and either get a strong reference or null.)
Example (with lock(); easy enough to adapt to the other style):
void do_something(weak_ptr<foo> weak) {
// Grab strong reference
shared_ptr<foo> strong(weak.lock());
if (strong) {
// We now have a strong reference to use
} else {
// No strong references left; object already freed
}
}
Both boost::weak_ptr and boost::shared_ptr are similar if it comes to thread safety: they are not thread safe if there is a risk that object is going to be destroyed somewhere. If your object referenced in boost::shared_ptr or weak_ptr is being referenced permanently somewhere, then use can use shared/weak ptrs without any risk.
But if some operation is going to dereference the last living instance of object, then at that time you cannot do some operations on weak_ptr: in particular: you cannot assign weak_ptr to another weak_ptr because it uses shared_ptr internally. Also, you cannot use lock because the result is undefined. Also, expired() method is useless to: it may return true, but then next line of your code, your object might be already expired.
Yes, ish. In terms of accessing the pointers, Boost should have made everything safe; that's part of their point.
However, if you're expecting to have a delay between when the last shared_ptr goes out, and when you want to make the next one, you'll get a null pointer. (If you're checking appropriately, you should then have an appropro fail case).
But you can't end up with an invalid shared_ptr