How does unique pointer ensure uniqueness? - c++

std::unique_ptr is a smart pointer that retains sole ownership of an object through a pointer and destroys that object when the unique_ptr goes out of scope. No two unique_ptr instances can manage the same object.
How the last statement is ensured?
I don't believe that there is "someone" is STL who checks if one of the already existing std::unique_ptrs already own the raw pointer. This would be very inefficient with huge number of unique pointers, even if it is a linear complexity algorithm. There should be a nice trick, right?

It isn't ensured. The name is a statement of intended usage, not any guarantee fully enforced by a runtime system. That is, you can write this code:
std::unique_ptr<int> i1(new int());
std::unique_ptr<int> i2(i1.get());
and you have two unique_ptrs referring to the same object, but the program has undefined behavior because it will delete the pointer twice.
unique_ptr is not copyable to make it harder to create two such pointers by accident. C++ protects against Murphy, not Machiavelli.

The reason it's called unique is because you can't copy a unique pointer. You can steal its value, but that leaves the original unique_ptr empty.

Related

Question about move-aware container and std::unique_ptr

As per the document, which says that:
std::unique_ptr is commonly used to manage the lifetime of objects, including:
as the element type in move-aware containers, such as std::vector,
which hold pointers to dynamically-allocated objects (e.g. if
polymorphic behavior is desired) [emphasis mine]
How to understand it in the right way?
Some simple example may helps.
Thanks.
This statement refers to the fact that it was notoriously unsafe to use std::auto_ptr as an element in containers. std::auto_ptr is deprecated already since C++11, but before that there was no move semantics in C++, and auto_ptr was the only "smart" pointer that was really standartized.
std::auto_ptr was similar to std::unique_ptr in that it was destroying the underlying object in the destructor. In contrast to the unique pointer, auto pointer allowed copying: the ownership of the object was transferring to the destination, while the source object was losing the ownership, still pointing to the object. This behavior was unsafe in containers: while you may rely on that the container of auto pointers keeps the ownership, you may easily lose it by simple access to the element (imagine what would happen when you would access the element next time after the actual temporary owner would be destroyed).
It worth mentioning that the STL library provided by Visual Studio C++ 6.0 had a different implementation of auto_ptr: instead of transferring the ownership this "smart" pointer was transferring everything, even the pointer value itself. That meant that the source auto_ptr was becoming empty after the assignment to another "copy" of this pointer. That was safer to store the objects like that in a container, but it caused other problems anyway.
Overall, the problems with usage auto_ptr in containers was [probably] the main reasons why std::auto_ptr was deprecated in C++11.
Returning back to std::unique_ptr: it is safe to use it in containers, and the standard clearly makes an explicit statement referring to the previous problems with std::auto_ptr.

Why calling shared_from_this calls std::terminate

Consider this code:
class A : public std::enable_shared_from_this<A>
{
public:
std::shared_ptr<A> f()
{
return shared_from_this();
}
};
int main()
{
A a;
std::shared_ptr<A> ptr = a.f();
}
This code terminated in Visual Studio 2017. I guess I am doing something wrong here. Can anyone help me with this? I want a shared_ptr on a created by shared_from_this().
Because a is not a owned by a shared pointer. From cppreference:
It is permitted to call shared_from_this only on a previously shared object, i.e. on an object managed by std::shared_ptr. Otherwise the behavior is undefined (until C++17)std::bad_weak_ptr is thrown (by the shared_ptr constructor from a default-constructed weak_this) (since C++17).
You cannot use shared_from_this to generate a new shared pointer. You already have to have an existing shared pointer to get a new one:
std::shared_ptr a(new A());
auto ptr = a->f(); // ok, 'ptr' shares ownership of newed object with 'a'
The issue is fundamental in the design (not technical details)
Whatever the exact specification of that C++ standard version you are using, what you are trying to do is impossible. Knowing the fine details of the specification of shared_from_this isn't needed to conclude that the code contains a design contradiction: just understanding the intent, which is to obtain a shared_ptr<A> to this, inside a member function called on a, an automatic object, is enough to determine that the design is in error.
In fact, any attempt at making an owning smart pointer (incl. but not limited to unique_ptr, shared_ptr) that points to (that owns) an object with "scoped" lifetime, that is an object whose lifetime is defined by the scope of the declaration of the object and ended by exiting something:
automatic objects (lifetime ends when exiting the scope),
namespace scope objects, static object members of classes (lifetime ends at program exit),
non static members of classes (lifetime ends when the body of the destructor of the containing class object exits),
is a design error, because the:
these objects were not created with any variant new (plain operator new or nothrow variant) that permits the call of delete on the result);
the only case where C++ allows you to destroy such object is by destruction followed (preferably immediately) by reconstruction with placement new of an object with the same complete type, which is obviously not the job of an owning smart pointer;
the compiler will destroy that object when program execution reach the exit point (exits scope, exits destructor, or std::exit, or return from main), no matter what (even if your owning smart pointer already took care of it); trying to destroy an already destroy object is not OK.
This includes constructing a smart pointer that owns (i.e. that promises to delete) a member of a class instance that was dynamically allocated:
struct A {
int m;
};
#define OK 1
void f() {
A *p = new A;
#if OK
std::shared_ptr<A> own (p); // fine
#else
std::shared_ptr<int> own (&p->m); // bad
#endif
}
Here the lifetime of the object pointed to by p is managed dynamically; the timing of the destruction of determined explicitly, by program code, and the lifetime of the unique member m is intrinsically linked to the lifetime of the A object; but the member itself need not be destructed explicitly and shall not be deleted. If the OK preprocessor constant is 1, all is well; if it is 0, you are trying to manage explicitly the lifetime of a member, which is unsound.
About the term "explicit" call to delete: although th delete operator never appears in the code, its call is implicit on the use of std::shared_ptr; in other words, std::shared_ptr explicitly uses delete, so use of std::shared_ptr (or other similar owning smart pointers) are indirect use of delete.
Safely sharing ownership with a smart pointer
The only safe way to share ownership of a shared_ptr is to make one from another shared_ptr, directly, or indirectly. This is the fundamental property of shared_ptr: all instances pointing to the one object must be traceable back to the one instance that one constructed with a raw pointer (or alternatively with make_shared).
This is a direct consequence of the fact that the ownership information (usually a reference count, but could be a linked list if you love inefficient implementations) is not inside the managed object, but inside the information block created by shared_ptr. This is not a property of just std::shared_ptr, it's a fact of life of all these externally managed objects, without a global registry, it's impossible to find the manager.
The basic design decision of these smart pointer is that the managed object need not be modified to use a smart pointer; hence they can be used on existing data type (incl. fundamental types).
Importance of weak copies of a shared owning manager
The fundamental property of shared_ptr would create an issue: as every layer of code (that might need to call a function that needs an owning pointer) needs to keep a copy of the shared_ptr around, this can create a web of owning smart pointers, some of which might reside in an object whose lifetime is managed by another who lifetime is managed by that exact smart pointer; because the smart pointer basic specification is that the managed object is not destructed before all copies of the smart pointer in charge of its destruction are destroyed, these objects would never be destroyed (as specified; this is not a consequence of the particular implementation choice of reference counting). Sometimes a copy of a owning smart pointer of a specie that doesn't prevent influence the lifetime of the managed object is needed, hence the need for the weak smart pointer.
A (non null) weak smart pointer is always directly or indirectly a copy of an owning smart pointer, directly or indirectly a copy the original smart pointer that took ownership. That "weak reference" actually is a "strong" owning smart pointer to the information regarding the existence of other owning copies of the smart pointer: as long as there is a weak smart pointer, it will be possible to determine whether there is a live owning smart pointer, and if so to obtain a copy, that is make a shared smart pointer that an exact copy of the original (the lifetime of the original may have ended many generations of copies ago).
The only purpose of a weak smart pointer is to obtain such copies of the original.
The purpose of std::enable_shared_from_this
The only use of std::enable_shared_from_this is to obtain a copy of the original shared_ptr; that implies that such owning smart pointer must already exist. No new original (another smart pointer taking ownership) will be made.
Only use std::enable_shared_from_this for classes that are only intended to be managed by a shared_ptr.
Details of std::enable_shared_from_this
All that being said about the theoretical principles, it's useful to understand what std::enable_shared_from_this contains, how it can produce a shared_ptr when used correctly (and why it cannot be expected to work in any other case).
The "magic" of std::enable_shared_from_this may seem mysterious, and too magic so that users don't have to think about it, but it's actually extremely simple: it keeps a weak_ptr intended to be a copy of the original. Obviously it cannot be constructed as such copy, as the original cannot even be initialized when the std::enable_shared_from_this subobject is constructed: a valid owning smart pointer can only refer to a fully constructed object, because it owns it and is in charge of its destruction. [Even if by some cheating an owning smart pointer was made before the managed object was fully constructed, and hence destructible, the owning smart pointer would be a risk of premature destruction (even if during the normal course of events its lifetime is long, it could be shortened by an exception for example).]
So data member initialization in std::enable_shared_from_this is inherently default initialization: the "weak pointer" is null at that point.
Only when the original finally takes ownership if the managed object, it can collude with std::enable_shared_from_this: the constructing of the original shared_ptr will set once and for all the weak_ptr member inside std::enable_shared_from_this. Active collusion between these components is the only way to make the stuff work.
It's still the user's responsibility to only call shared_from_this only when it can possibly return a copy of the original, that is, after the original has been constructed.
About fake (non owning) owning smart pointers
A fake owning smart pointer is one that does no cleanup ever: owning smart pointer in name only. They are special case of "owning" smart pointers used in such a way that no destruction or cleanup is performed. This ostensibly means that they could be used for objects whose lifetime is predetermined (and long enough) and for which there is a need to have a pretend owning smart pointer; unlike a real owning smart pointer, keeping a copy will not extend the lifetime of the object, so that lifetime should better be really long. (Because a copy of a owning smart pointer could be stored in a global variable, the object could still be expected to be alive after a return from main.)
These non owning owners are obviously a contradiction in the terms and rarely safe (but can be proven safe in a few cases).
They rarely solve a legitimate problem (one that isn't the immediate consequence of a very bad design): a shared_ptr in an interface means that the receiver is expecting to be able to extend the lifetime of the managed object.

How do I pass smart pointers into functions?

When passing objects into functions, do the same rules apply to smart pointers as to other objects that contain dynamic memory?
When I pass, for example, a std::vector<std::string> into a function I always consider the following options:
I'm going to change the state of the vector object, but I do not want those changes reflected after the function has finished, AKA make a copy.
void function(std::vector<std::string> vec);
I'm going to change the state of the vector object, and I do want those changes reflected after the function has finished, AKA make a reference.
void function(std::vector<std::string> & vec);
This object is pretty big, so I'd better pass a reference, but tell the compiler not to let me change it.
void function(std::vector<std::string> const& vec);
Now is this the same logic with smart pointers? And when should I consider move semantics? Some guidelines on how I should pass smart pointers is what I desire most.
Smart pointers have pointer semantics, not value semantics (well, not the way you mean it). Think of shared_ptr<T> as a T*; treat it as such (well, except for the reference counting and automatic deletion). Copying a smart pointer does not copy the object it points to, just like copying a T* does not copy the T it points to.
You can't copy a unique_ptr at all. The whole point of the class is that it cannot be copied; if it could, then it wouldn't be a unique (ie: singular) pointer to an object. You have to either pass it by some form of reference or by moving it.
Smart pointers are all about ownership of what they point to. Who owns this memory and who will be responsible for deleting it. unique_ptr represents unique ownership: exactly one piece of code owns this memory. You can transfer ownership (via move), but in so doing, you lose ownership of the memory. shared_ptr represents shared ownership.
In all cases, the use of a smart pointer in a parameter list represents transferring ownership. Therefore, if a function takes a smart pointer, then it is going to claim ownership of that object. If a function isn't supposed to take ownership, then it shouldn't be taking a smart pointer at all; use a reference (T&) or if you have need of nullability, a pointer but never store it.
If you are passing someone a unique_ptr, you are giving them ownership. Which means, by the nature of unique ownership, you are losing ownership of the memory. Thus, there's almost no reason to ever pass a unique_ptr by anything except by value.
Similarly, if you want to share ownership of some object, you pass in a shared_ptr. Whether you do it by reference or by value is up to you. Since you're sharing ownership, it's going to make a copy anyway (presumably), so you might as well take it by value. The function can use std::move to move it into class members or the like.
If the function isn't going to modify or make a copy of the pointer, just use a dumb pointer instead. Smart pointers are used to control the lifetime of an object, but the function isn't going to change the lifetime so it doesn't need a smart pointer, and using a dumb pointer gives you some flexibility in the type used by the caller.
void function(std::string * ptr);
function(my_unique_ptr.get());
function(my_shared_ptr.get());
function(my_dumb_ptr);
unique_ptr can't be copied without invalidating the original, so if you must pass it you must pass a reference.
For a more in-depth look at this recommendation by someone a lot smarter than me, see Herb Sutter's GotW #91 Solution: Smart Pointer Parameters. He goes beyond this recommendation and suggests that if the pointer can't be null, you should pass by reference instead of pointer. This requires dereferencing the pointer at the site of the call.
void function(std::string & val);
assert(my_unique_ptr != nullptr && my_shared_ptr != nullptr && my_dumb_ptr != nullptr);
function(*my_unique_ptr);
function(*my_shared_ptr);
function(*my_dumb_ptr);
A smart pointer is an object that refer to another object an manages its lifetime.
Passing a smart pointer reuquires to respect the semantics the smart poitner support:
Passing as const smartptr<T>& always work (and you cannot change the pointer, but can change the state of what it points to).
Passing as smartptr<T>& always work (and you can change the pointer as well).
Passing as smartptr<T> (by copy) works only if smartptr is copyable. It works with std::shared_ptr, but not with std::unique_ptr, unless you "move" it on call, like in func(atd::move(myptr)), thus nullifying myptr, moving the pointer to the passed parameter. (Note that move is implicit if myptr is temporary).
Passing as smartptr<T>&& (by move) imposes the pointer to be moved on call, by forcing you to explicitly use std::move (but requires "move" to make sense for the particular pointer).
I know the person asked this question is more knowledgeable than me in C++ and There are some perfect answer to this question but I believe This question better be answer in a way that it doesn't scares people from C++, although it could get a little complicated, and this is my try:
Consider there is only one type of smart pointer in C++ and it is shared_ptr, so we have these options to pass it to a function:
1 - by value : void f(std::shared_ptr<Object>);
2 - by reference : void f(std::shared_ptr<Object>&);
The biggest difference is ,the First one lend you the ownership and The second one let you manipulate the ownership.
further reading and details could be at this link which helped me before.

Missing equality between shared_ptr and weak_ptr

While I do understand why there is no operator== for shared_ptr and unique_ptr, I wonder why there is none for shared_ptr and weak_ptr. Especially since you can create a weak_ptr via a reference on shared_ptr.
I would assume that for 99% of the time you want lhs.get() == rhs.get(). I would now go forward and introduce that into my code unless someone can name me a good reason, why one should not do such a thing.
weak_ptr doesn' have a get() method because you need to explicitly lock the weak_ptr before you can access the underlying pointer. Making this explicit is a deliberate design decision. If the conversion were implicit it would be very easy to write code that would be unsafe if the last shared_ptr to the object were to be destroyed while the underlying pointer obtained from the weak_ptr was still being examined.
This boost page has a good description of the pitfalls and why weak_ptr has such a limited interface.
If you need to do a quick comparison, then you can do shared == weak.lock(). If the comparison is true then you know that weak must still be valid as you hold a separate shared_ptr to the same object. There is no such guarantee if the comparison returns false.
Because it has a cost.
A weak_ptr is like an observer, not a real pointer. To do any work with it you first need to obtain a shared_ptr from it using its lock() method.
This has the effect of acquiring ownership, but it as costly as copying a regular shared_ptr (count increment, etc...) so it is nothing trivial.
As such, by not providing ==, you are forced to step back and actually check whether you really need this or not.
As the other answers have pointed out, simply comparing the underlying pointers would be perilous. For one, consider the following scenario: a weak reference A exists to an object, which is subsequently deleted, and therefore the weak reference expires. Then, another object is allocated in the memory freed up by said deletion, which has the same address. Now the underlying pointers are the same, even though the weak pointer originally referred to a different object!
As the other answers have suggested, one way is to compare shared == weak.lock(). Since lock() will return nullptr (and not some bogus pointer) if the weak pointer expired, his works for identifying if they are equal (as long as shared != nullptr). However, there are two problems with this:
It stops working when the weak pointer expires, in which case the comparison changes; after the expiration, it will only return true if shared == nullptr. This can be dangerous in cases where the comparison must remain stable, such as when using it as a key in an unordered_map or unordered_set.
lock() is a relatively expensive operation.
Fortunately, there is a better way to do this. Both weak_ptr and shared_ptr also store a pointer to what is known as the control block, which is what stores the reference counts and outlives the original object for as long as references remain to it. To check whether they refer to the same object, all we need to do is compare the control block pointers. This can be done with the owner_before method:
template<class T>
bool owner_equals(std::shared_ptr<T> &lhs, std::weak_ptr<T> &rhs) {
return !lhs.owner_before(rhs) && !rhs.owner_before(lhs);
}
This approach will even work for comparing two std::weak_ptrs with each other, if you wish to know whether they (once) referred to the same object, since the control block will last (at least) as long as all of the weak references.
Do keep in mind that this may not produce the expected result if you are using the aliasing feature of std::shared_ptr, which is a feature that lets you create two std::shared_ptr instances with the same control block that nonetheless store different pointers.

Can deriving a class from 'enable_shared_from_this' increase performance?

make_shared is more performant than separately calling new and creating a shared_ptr because make_shared allocates space for the reference count and weak count in the same memory block as the client object instance (effectively giving the shared_ptr most of the performance benefits of an intrusive_ptr).
enable_shared_from_this gives a shared pointer without having a reference to any shared pointer. Therefore things like the reference and weak count have to be somehow accessible from inside the client object. Therefore, it would be sensible for enable_shared_from_this to cause an intrusive count similar to make_shared.
However, I have no idea how something like that might be implemented (and I'm not sure I'd follow what was going on in there even if I look at the actual source).
Would it make sense then (for performance reasons) to tag my class with enable_shared_from_this if I know it's only ever going to be used as a shared_ptr and never as a raw object?
I have never dug into the details of implementation, but for shared_from_this to work, the object must already be managed by an external shared_ptr, so it is to some extent unrelated. I.e. the first shared_ptr might have been created with make_shared in which case the count and object are together (as you say intrusive pointer like), but that does not need to be the case.
My first guess is that enable_shared_from_this adds the equivalent of a weak_ptr, rather than a shared_ptr. EDIT: I have just verified the implementation in gcc4.6:
template <typename _Tp>
class enable_shared_from_this {
...
mutable weak_ptr<_Tp> _M_weak_this;
};
I don't believe so. How enable_shared_from_this is implemented isn't strictly defined, but an example implementation is present in the standard that corresponds to how boost does it. Basicaly, there is a hidden weak_ptr that shared_ptr and friends has access to... anytime a shared_ptr is given ownership of an object derived from enable_shared_from_this, it updates that internal pointer. Then shared_from_this() simply returns a strong version of that weak pointer.
In the general case, the implementation can't really assume that nobody will ever go shared_ptr(new T) instead of using make_shared, so an intrusive reference count would be risky. You can instead make that guarentee yourself, by whatever means you use to construct the objects in the first place.
Boost's enable_shared_from_this does not change the implementation of shared_ptr itself. Remember that shared_ptr is paired with weak_ptr - this means that, even after the object is deleted, the tracking data may need to remain around to tell the weak_ptr that the object is dead. As such, it can't be embedded into the object, even with enable_shared_from_this. All enable_shared_from_this does is embed a pointer to said tracking data into the object, so a shared_ptr can be constructed with just a pointer to the object.
This is also why intrusive_ptr cannot have a weak_intrusive_ptr variant.