std::unique_ptr uniquely controls the object it points to and, hence, does not utilize reference counting. A singleton ensures only one object may be created utilizing reference counting.
Would then std::unique_ptr perform identically to a singleton?
A singleton ensures only one instance of a type.
A unique_ptr ensures only one smart pointer to any instance.
Would then std::unique_ptr perform identically to a singleton?
No. Let's say we have class Foo that's intended to be a singleton. Using a typical singleton pattern, there's no way to construct more than one Foo.
Having a std::unique_ptr<Foo> means there will be one pointer to a particular instance of Foo, but that doesn't prevent the creation of other instances of Foo (either with other unique_ptrs or with raw pointers to local variables). Thus Foo, wouldn't be a singleton.
std::unique_ptr achieves single ownership semantics by only providing a move constructor and no copy constructor or assignment operator.
It is not a case of singleton at all, since you can have multiple unique_ptrs referencing different instances of the same type. A singleton doesn't let you construct the type directly, but provides an accessor that manages a sole instance.
Also, Drew's assertion that
"A unique_ptr ensures only one smart pointer to any instance."
is false. If you simply do:
T* nt = new T;
std::unique_ptr<T> up1(nt);
std::unique_ptr<T> up2(nt);
then you have two unique pointers owning the same resource - and you will only notice a problem at run time, not compile time. Of course, this is incorrect usage of unique_ptr, but this reinforces that a unique_ptr does not ensure you anything, it is simply a pointer container that holds sole ownership from its own perspective, and through its api, makes it hard to accidentally create temporary copies.
Furthermore, you can have other (smart) pointer types pointing to the same raw pointer/resource independently of any unique_ptr. It is completely up to the using code to define ownership and lifetime policies of its resources and smart pointer instances
Correct me if I'm wrong, but as far as I remember a singelton is a class which can only have one instance. That's completely different. So no.
Related
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.
Currently i am thinking about storing some member objects in unique_ptr.
Normally i use unique_ptr just in some functions and move it around, or pass references to it.
So how should i do in classes?
Class MyClass {
std::unique_ptr<MyMemberClass> member;
}
or:
Class MyClass {
MyMemberClass member;
}
The lifetime of the object is the same. The initialization in the constructor would be nearly the same.
The only difference is, that i can't copy the unique_ptr, or?
Are there other differences?
And which should i use or prefer?
Are there other differences? And which should i use or prefer?
Yes.
The deciding factors here are:
polymorphic behavior : If you store the common interface for a class hierarchy, then you should store by pointer, smart pointer or reference.
lifetime : as you mentioned, if the held object has a longer lifetime than MyClass (and obviously, it is not owned by MyClass) then it should be held in a raw pointer or a std::shared_ptr.
ownership : if the object is not owned by MyClass, then it should be stored as a pointer (smart or not) or a reference.
api constraints: if the held object is generated by a library that can only allocate it dynamically (for example), then you will probably want to hold it in a pointer (or unique_ptr).
When the object is owned (exclussively) by MyClass, it has the same lifetime as the owning class, and you do not have polymorphic behavior, you should probably store the instance directly.
Differences:
1) You can't copy class with unique_ptr (you can actually, but this has no sense), but you can move.
2) If member is unique_ptr, MyMemberClass object should be allocated on heap, when in second case it's allocated on stack (when object of type MyClass is allocated on stack).
3) If member is complicated object, than probably store pointer on it is better, in other case just object is fine.
4) If member is unique_ptr it can be a polymorphic object. It allows to create an aggregate object. With the second form it is not possible (thanks to chmike).
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.
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.
This is a simplified example to illustrate the question:
class A {};
class B
{
B(A& a) : a(a) {}
A& a;
};
class C
{
C() : b(a) {}
A a;
B b;
};
So B is responsible for updating a part of C. I ran the code through lint and it whinged about the reference member: lint#1725.
This talks about taking care over default copy and assignments which is fair enough, but default copy and assignment is also bad with pointers, so there's little advantage there.
I always try to use references where I can since naked pointers introduce uncertaintly about who is responsible for deleting that pointer. I prefer to embed objects by value but if I need a pointer, I use auto_ptr in the member data of the class that owns the pointer, and pass the object around as a reference.
I would generally only use a pointer in member data when the pointer could be null or could change. Are there any other reasons to prefer pointers over references for data members?
Is it true to say that an object containing a reference should not be assignable, since a reference should not be changed once initialised?
My own rule of thumb :
Use a reference member when you want the life of your object to be dependent on the life of other objects : it's an explicit way to say that you don't allow the object to be alive without a valid instance of another class - because of no assignment and the obligation to get the references initialization via the constructor. It's a good way to design your class without assuming anything about it's instance being member or not of another class. You only assume that their lives are directly linked to other instances. It allows you to change later how you use your class instance (with new, as a local instance, as a class member, generated by a memory pool in a manager, etc.)
Use pointer in other cases : When you want the member to be changed later, use a pointer or a const pointer to be sure to only read the pointed instance. If that type is supposed to be copyable, you cannot use references anyway. Sometimes you also need to initialize the member after a special function call ( init() for example) and then you simply have no choice but to use a pointer. BUT : use asserts in all your member function to quickly detect wrong pointer state!
In cases where you want the object lifetime to be dependent on an external object's lifetime, and you also need that type to be copyable, then use pointer members but reference argument in constructor That way you are indicating on construction that the lifetime of this object depends on the argument's lifetime BUT the implementation use pointers to still be copyable. As long as these members are only changed by copy, and your type don't have a default constructor, the type should fullfil both goals.
Avoid reference members, because they restrict what the implementation of a class can do (including, as you mention, preventing the implementation of an assignment operator) and provide no benefits to what the class can provide.
Example problems:
you are forced to initialise the reference in each constructor's initialiser list: there's no way to factor out this initialisation into another function (until C++0x, anyway edit: C++ now has delegating constructors)
the reference cannot be rebound or be null. This can be an advantage, but if the code ever needs changing to allow rebinding or for the member to be null, all uses of the member need to change
unlike pointer members, references can't easily be replaced by smart pointers or iterators as refactoring might require
Whenever a reference is used it looks like value type (. operator etc), but behaves like a pointer (can dangle) - so e.g. Google Style Guide discourages it
Objects rarely should allow assign and other stuff like comparison. If you consider some business model with objects like 'Department', 'Employee', 'Director', it is hard to imagine a case when one employee will be assigned to other.
So for business objects it is very good to describe one-to-one and one-to-many relationships as references and not pointers.
And probably it is OK to describe one-or-zero relationship as a pointer.
So no 'we can't assign' then factor.
A lot of programmers just get used with pointers and that's why they will find any argument to avoid use of reference.
Having a pointer as a member will force you or member of your team to check the pointer again and again before use, with "just in case" comment. If a pointer can be zero then pointer probably is used as kind of flag, which is bad, as every object have to play its own role.
Use references when you can, and pointers when you have to.
In a few important cases, assignability is simply not needed. These are often lightweight algorithm wrappers that facilitate calculation without leaving the scope. Such objects are prime candidates for reference members since you can be sure that they always hold a valid reference and never need to be copied.
In such cases, make sure to make the assignment operator (and often also the copy constructor) non-usable (by inheriting from boost::noncopyable or declaring them private).
However, as user pts already commented, the same is not true for most other objects. Here, using reference members can be a huge problem and should generally be avoided.
As everyone seems to be handing out general rules, I'll offer two:
Never, ever use use references as class members. I have never done so in my own code (except to prove to myself that I was right in this rule) and cannot imagine a case where I would do so. The semantics are too confusing, and it's really not what references were designed for.
Always, always, use references when passing parameters to functions, except for the basic types, or when the algorithm requires a copy.
These rules are simple, and have stood me in good stead. I leave making rules on using smart pointers (but please, not auto_ptr) as class members to others.
Yes to: Is it true to say that an object containing a reference should not be assignable, since a reference should not be changed once initialised?
My rules of thumb for data members:
never use a reference, because it prevents assignment
if your class is responsible for deleting, use boost's scoped_ptr (which is safer than an auto_ptr)
otherwise, use a pointer or const pointer
I would generally only use a pointer in member data when the pointer could be null or could change. Are there any other reasons to prefer pointers over references for data members?
Yes. Readability of your code. A pointer makes it more obvious that the member is a reference (ironically :)), and not a contained object, because when you use it you have to de-reference it. I know some people think that is old fashioned, but I still think that it simply prevent confusion and mistakes.
I advise against reference data members becasue you never know who is going to derive from your class and what they might want to do. They might not want to make use of the referenced object, but being a reference you have forced them to provide a valid object.
I've done this to myself enough to stop using reference data members.