Member Objects as unique_ptr or on Stack - c++

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

Related

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.

singleton pattern and std::unique_ptr

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.

Can I use placement new to reset an object within a shared_ptr?

Let's say I have a class.
class BigData {...};
typedef boost::shared_ptr<BigData> BigDataPtr;
Then I do:
BigDataPtr bigDataPtr(new BigData());
Later on after I am done with my object and I am sure there no other users for the object.
Is it safe to do the following:
bigDataPtr->~BigDataPtr();
new (&*bigDataPtr) BigData;
Would this let me reset the object without any additional allocations?
There are a few ways to go about this. You can use placement new, and this is guaranteed to be safe for two reasons:
You have already allocated the memory for the object, so you know it’s sized and aligned correctly.
shared_ptr is non-invasive; its sole responsibility is to count references and call the deleter when necessary.
However, consider what can happen if reconstruction of the object fails—i.e., throws an exception:
bigDataPtr->~BigDataPtr();
new (bigDataPtr.get()) BigData;
Then you have a problem: the deleter can be called on a non-constructed object, leading almost certainly to undefined behaviour. I say “almost” because the deleter could be a no-op, in which case all would be well.
Safer, I think, would be to move a new value into the existing object:
*bigDataPtr = BigData(42);
Or add a reset() member function to BigData:
bigDataPtr->reset(42);
Then it’s explicit what your real intent is, and you don’t need to be as concerned about object lifetimes.
Yes it is normally safe. (Nod to Maxim Yegorushkin's observation about a throwing edge case)
Note the typo message below
Boost defines the dereference and -> operators as
template<class T>
typename boost::detail::sp_dereference< T >::type boost::shared_ptr< T >::operator* () const;
template<class T>
typename boost::detail::sp_member_access< T >::type boost::shared_ptr< T >::operator-> () const;
When those detail bits are resolved, you have this
template<class T>
T & boost::shared_ptr< T >::operator* () const
template<class T>
T * boost::shared_ptr< T >::operator-> () const
So you are dealing with the pointed-to object directly. There are no proxies or other constructs that may interfere with what you're attempting.
As the pointed-to data is concerned, your code:
bigDataPtr->~BigDataPtr();
new (&*bigDataPtr) BigData;
May have a typo. But if you intended:
bigDataPtr->~BigData();
new (&*bigDataPtr) BigData;
It will resolve to
(BigData pointer)->~BigData();
new (&(BigData reference)) BigData;
This is legal, and you are correct that it would avoid the additional allocation normally incurred with an assignment.
It is safe if BigData constructor and destructor do not throw exceptions and bigDataPtr is not shared between threads and no pointers or references exist to dynamically allocated members of BigData (if any).
If the destructor throws an exception you may end up with a partially destroyed object (throwing destructors are not generally recommended and standard containers require that destructors of elements do not throw).
If the constructor throws you may end up destroying the object but not constructing a new one.
If bigDataPtr is shared between threads that may also lead to a race condition unless a locking discipline is used.
If code elsewhere takes references or pointers to dynamically allocated members of BigData, when it creates a new BigData its dynamically allocated members may be allocated at other addresses, so existing pointers and references to the members become invalid.
If you are concerned with dubious dereference in new (&*bigDataPtr) BigData; statement use a plain pointer instead:
BigData* p = bigDataPtr.get();
p->~BigData();
new (p) BigData;
Firstly, if the constructor throws and the class is not trivially destructible then you have a problem, since the shared_ptr "wants" to delete it, which would provoke UB.
So you must deal with that, either by using a nothrow constructor or by catching any exception and preventing the smart pointer from deleting the object. Since shared_ptr doesn't have a release() function, that's easier said than done. You could call terminate() if all else fails, but that won't make you popular with your users.
If there are no other references to the object, then it will work provided that the class has no const or reference non-static data members (including members-of-members). The reason is 3.8/7:
If, after the lifetime of an object has ended and before the storage
which the object occupied is reused or released, a new object is
created at the storage location which the original object occupied, a
pointer that pointed to the original object ... can be used to
manipulate the new object, if ... the type of the original object is
not const-qualified, and, if a class type, does not contain any
non-static data member whose type is const-qualified or a reference
type ...
Note that the shared_ptr holds just such a pointer, which it will use to manipulate the new object, which is UB if any of the conditions in 3.8/7 is broken. The only one that might be broken is this one, you've covered the rest with what you've said about your code. In particular, it's required that you created the original object as an instance of BigData, not a class derived from BigData, because the new object is required to have the same most-derived type as the old one.
There are usually more robust ways to reset an object than this. For example, implement operator= (copy- or move assignment operator) and then write *bigDataPtr = BigData(). Of course that might not be quite as fast.

in C++, what's the difference between an object and a pointer to an object?

In java and objective-c, a variable representing an object is generally a pointer to that object. However, it seems that in C++, it's common to have non-pointer types hold objects. What's the difference between the two?
If I pass a struct as an argument to a function, I believe I'm passing by value, meaning I'm actually creating a new struct in memory, and changes to that struct inside the function its passed to won't affect the "source" struct outside the function. However, if I pass a pointer to a struct, there's still only one original struct, and changes to the struct referenced by the pointer will be visible to any code which is aware of this struct. Do I have that right?
So, is there any difference with objects? When I pass a non-pointer object to a function, does the entire object get copied?
It's exactly as you said.
When you pass an object by value, its copy constructor is invoked to produce a new instance of such object that will be used inside the function. The changes done to such new object won't be reflected to the original one1.
As with structures, the default copy constructor just does a shallow copy of the original object - i.e., its fields are copied2 to the new instance; in many cases this is not desirable (e.g. if the object wraps a pointer/another resource), so there are classes which redefine the copy constructor or disable it completely. Objects of these last classes can only be passed by pointer or reference.
Passing objects by value can be costly if they are bigger than a pointer (in size) or in general if their copy constructor isn't "cheap". On the other hand, in comparison to pointers, the pass-by-value yields the usual advantages of not having to specify the pointer ownership, letting the callee do whatever it wants with the object, etc.
Notice that passing an object by value kills the polymorphism. This because a function receiving an object by value receives a statically typed object, with a precise size and type, so any attempt to pass an object of a derived class will result in object slicing (the copy constructor for the base class is called, that by default just copies the fields that are available in the base class).
This is the reason why often the preferred method of passing objects is by const reference. This yields several advantages:
no copies involved; the object that the callee will see will be exactly the one specified at the moment of the call;
no changes to the original object can be made, thanks to the const qualifier;
if however the callee needs to change a copy of the object, it can still construct a copy by itself from the reference;
no awkward pointer syntax;
polymorphism preserved, since behind the scenes we're actually passing a pointer;
no big doubts about object ownership: the general rule about references is that they are owned by the caller.
As far as the "raw fields" of the object are concerned; naturally if the original object and the copy continue to share a pointer/handle to the same resource some modifications to one may affect the other.
Primitive types (and in general PODs) are copied bitwise, while the copy constructor is called for non-POD types.
The difference mostly has to do with where in memory an object is allocated. For instance:
int main() {
MyObject x; //allocates space for an instance of MyObject on the stack
MyObject* y; //allocates space for a pointer on the stack
MyObject* z = new MyObject(); //allocates space for a pointer on the
//stack and an object instance in the heap and
//sets the pointer to point to the new instance
MyObject* a = &x; //allocates space for a pointer on the stack and
//makes it point to 'x'
...
}
int someFunc(MyObject byValue, MyObject* byReference) {
//the 'byValue' parameter will be passed by creating a copy of the
//entire source object on the stack (can be quite expensive for
//complex object types)
//the 'byReference' parameter will be passed by creating a
//copy of the source pointer on the stack and setting it to
//point to the source object in memory
}
In C++, a variable is the variable that it is representing. It is the actual object in memory, at the actual location.
However, you can choose to make such a variable represent a pointer instead, in which case it'll say "Hey, I'm me, I am pointing over there! The object you want isn't here, it's THERE. Yes, there! Go on, get there!".
Unless you're explicitly using C++'s "reference type", which I suspect you're not, then ALL arguments you pass are by value.
The answers to the questions in your second and third paragraph are both "yes". More specifically, if you pass an object to a function by value, the function will receive a copy of that object (created by the copy constructor).
When you pass an object to a function by value, it's copied by means of its class's copy constructor. If you haven't defined a copy constructor, there'll be a default one supplied by the compiler (unless you take special steps to avoid that), which is equivalent to copying the members by hand.
The preferred thing to do is often actually to pass a const reference rather than either a pointer or the object itself.
(You might want to be aware that actually a struct is just a class whose members are public by default; in particular, structs can have user-defined copy constructors too. A struct is not necessarily just plain inert data.)
You have that right.
Indeed, that's how it works. A pointer stores the memory address of a variable.
When you pass a pointer (to an object) for a function as a parameter, it means that function will have access to that object through it's memory address instead of a new object being created on the stack.
Check this thread for more info on pointers.
A pointer stores an memory address.
A variable stores a value.
Ex:
Player * a; // Allocated an int value to stored an address, you will able to access to value at that address by a -> but you have to allocated it and free when it done
Player a; // Allocated a block of memory that size equal = Player size.

Are reference attributes destroyed when class is destroyed in C++?

Suppose I have a C++ class with an attribute that is a reference:
class ClassB {
ClassA &ref;
public:
ClassB(ClassA &_ref);
}
Of course, the constructor is defined this way:
ClassB::ClassB(ClassA &_ref) : ref(_ref) { /* ... */ }
My question is: When an instance of class 'ClassB' is destroyed, is the object referenced by 'ClassB::ref' also destroyed?
A reference is nothing but an alias for a variable, the alias gets destructed, not the actual variable. You could consider it some kind of pointer, but there are reasons to refrain from this kind of (evil) thoughts :).
No. Reference members do not affect the lifetime of whatever they point to. This means the thing they alias may have a longer or a shorter lifetime than that of the reference.
On the other hand, const references can affect the lifetime of what they point to if they point to a temporary.
In your case it does not.
No. That's why you need a ~ClassB destructor if ClassB is responsible for the storage of ref which it might not be.
When an object is eliminated in C++, its memory is deallocated and thus everything that was embedded in it (such as member variables) is lost as well.
In the case of a pointer, the pointer is a member variable that contains an address, so the address is "destroyed" but the referenced object, if any, is not.
In the case of a reference member, the address is destroyed, but the target is not affected.
A class may define a destructor that could define special behaviors. One common such behavior is to invoke cleanup operations on members (if any), and to deallocate memory that was dynamically allocated earlier. Here, however, you already got an object so you should not be the one deallocating it.
No; references are merely an alternate syntax for pointers. The value they reference won't be modified if the reference is deallocated.
If you want it to be destroyed, you will have to encapsulate it (normally done via "smart" pointers, like std::shared_ptr or std::unique_ptr), that will automatically release the memory in an appropriate fashion on destruction of B. In-language references have no memory freeing behaviour associated with them, except the actual memory of the reference itself, as opposed to the referred.
You will have to build and understand your own memory model. People typically use shared_ptr and reference counting for basic uses.
I don't have the C++ spec on hand, but my guess is "No".
Pointers aren't deleted automatically when an object is destroyed, I see no reason that a reference should be different. Plus, having the reference automatically destroyed would be ripe for interesting bugs.