C++ using scoped_ptr as a member variable - c++

Just wanted opinions on a design question. If you have a C++ class than owns other objects, would you use smart pointers to achieve this?
class Example {
public:
// ...
private:
boost::scoped_ptr<Owned> data;
};
The 'Owned' object can't be stored by value because it may change through the lifetime of the object.
My view of it is that on the one side, you make it clear that the object is owned and ensure its deletion, but on the flipside, you could easily just have a regular pointer and delete it in the destructor. Is this overkill?
Follow up: Just wanted to say thanks for all your answers. Thanks for the heads-up about auto_ptr leaving the other object with a NULL pointer when the whole object is copied, I have used auto_ptr extensively but had not thought of that yet. I make basically all my classes boost::noncopyable unless I have a good reason, so there's nothing to worry about there. And thanks also for the information on memory leaks in exceptions, that's good to know too. I try not to write things which could cause exceptions in the constructor anyway - there are better ways of doing that - so that shouldn't be a problem.
I just had another question though. What I wanted when I asked this question was to know whether anyone actually did this, and you all seem to mention that it's a good idea theoretically, but no one's said they actually do it. Which surprises me! Certainly one object owning a pointer to another is not a new idea, I would have expected you all would have done it before at some point. What's going on?

scoped_ptr is very good for this purpose. But one has to understand its semantics. You can group smart pointers using two major properties:
Copyable: A smart pointer can be copied: The copy and the original share ownership.
Movable: A smart pointer can be moved: The move-result will have ownership, the original won't own anymore.
That's rather common terminology. For smart pointers, there is a specific terminology which better marks those properties:
Transfer of Ownership: A smart pointer is Movable
Share of Ownership: A smart pointer is copyable. If a smart pointer is already copyable, it's easy to support transfer-of-ownership semantic: That then is just an atomic copy & reset-of-original operation, restricting that to smart pointers of certain kinds (e.g only temporary smart pointers).
Let's group the available smart pointers, using (C)opyable, and (M)ovable, (N)either:
boost::scoped_ptr: N
std::auto_ptr: M
boost::shared_ptr: C
auto_ptr has one big problem, in that it realizes the Movable concept using a copy constructor. That is because When auto_ptr was accepted into C++, there wasn't yet a way to natively support move semantics using a move constructor, as opposed to the new C++ Standard. That is, you can do the following with auto_ptr, and it works:
auto_ptr<int> a(new int), b;
// oops, after this, a is reset. But a copy was desired!
// it does the copy&reset-of-original, but it's not restricted to only temporary
// auto_ptrs (so, not to ones that are returned from functions, for example).
b = a;
Anyway, as we see, in your case you won't be able to transfer the ownership to another object: Your object will in effect be non-copyable. And in the next C++ Standard, it will be non-movable if you stay with scoped_ptr.
For implementing your class with scoped_ptr, watch that you either have one of these two points satisfied:
Write an destructor (even if it's empty) in the .cpp file of your class, or
Make Owned a completely defines class.
Otherwise, when you would create an object of Example, the compiler would implicitly define a destructor for you, which would call scoped_ptr's destructor:
~Example() { ptr.~scoped_ptr<Owned>(); }
That would then make scoped_ptr call boost::checked_delete, which would complain about Owned being incomplete, in case you haven't done any of the above two points. If you have defined your own dtor in the .cpp file, the implicit call to the destructor of scoped_ptr would be made from the .cpp file, in which you could place the definition of your Owned class.
You have that same problem with auto_ptr, but you have one more problem: Providing auto_ptr with an incomplete type is undefined behavior currently (maybe it will be fixed for the next C++ version). So, when you use auto_ptr, you have to make Owned a complete type within your header file.
shared_ptr doesn't have that problem, because it uses a polymorphic deleter, which makes an indirect call to the delete. So the deleting function is not instantiated at the time the destructor is instantiated, but at the time the deleter is created in shared_ptr's constructor.

It's a good idea. It helps simplify your code, and ensure that when you do change the Owned object during the lifetime of the object, the previous one gets destroyed properly.
You have to remember that scoped_ptr is noncopyable, though, which makes your class noncopyable by default until/unless you add your own copy constructor, etc. (Of course, using the default copy constructor in the case of raw pointers would be a no-no too!)
If your class has more than one pointer field, then use of scoped_ptr actually improves exception safety in one case:
class C
{
Owned * o1;
Owned * o2;
public:
C() : o1(new Owned), o2(new Owned) {}
~C() { delete o1; delete o2;}
};
Now, imagine that during construction of a C the second "new Owned" throws an exception (out-of-memory, for example). o1 will be leaked, because C::~C() (the destructor) won't get called, because the object has not been completely constructed yet. The destructor of any completely constructed member field does get called though. So, using a scoped_ptr instead of a plain pointer will allow o1 to be properly destroyed.

It's not overkill at all, it's a good idea.
It does require your class clients to know about boost, though. This may or may not be an issue. For portability you could consider std::auto_ptr which does (in this case) the same job. As it's private, you don't have to worry about other people attempting to copy it.

Using the scoped_ptr is a good idea.
Keeping and manually destroying the pointer is not as simple as you think. Especially if there is more than one RAW pointer in your code. If exception safety and not leaking memory is a priority then you need a lot of extra code to get it correct.
For a start you have to make sure you correctly define all four default methods. This is because the compiler generated version of these methods are fine for normal objects (including smart pointers) but in the normal case will lead to problems with pointer handling (Look for the Shallow Copy Problem).
Default Constructor
Copy Constructor
Assignment Operator
Destructor
If you use the scoped_ptr then you don't need to worry about any of those.
Now if you have more than one RAW pointer in your class (or other parts of your constructor can throw) . You have to EXPLICITLY deal with exceptions during construction and destruction.
class MyClass
{
public:
MyClass();
MyClass(MyClass const& copy);
MyClass& operator=(MyClass const& copy);
~MyClass();
private
Data* d1;
Data* d2;
};
MyClass::MyClass()
:d1(NULL),d2(NULL)
{
// This is the most trivial case I can think off
// But even it looks ugly. Remember the destructor is NOT called
// unless the constructor completes (without exceptions) but if an
// exception is thrown then all fully constructed object will be
// destroyed via there destructor. But pointers don't have destructors.
try
{
d1 = new Data;
d2 = new Data;
}
catch(...)
{
delete d1;
delete d2;
throw;
}
}
Look how much easier a scopted_ptr is.

Scoped pointers are good for exactly this because they ensure that the objects get deleted without you having to worry about it as a programmer. I think that this is a good use of scoped ptr.
I find that a good design strategy in general is to avoid freeing memory manually as much as possible and let your tools (in this case smart pointers) do it for you. Manual deletion is bad for one main reason as I can see it, and that is that code becomes difficult to maintain very quickly. The logic for allocation and deallocation of memory is often separate in the code, and that leads to the complementary lines not being maintained together.

I don't think this is overkill, this documents the semantics of the member much better than having a raw pointer and is less error prone.

Why an overkill? boost::scoped_ptr is very easy to optimize, and I bet the resulting machine code would be the same as if you manually delete the pointer in the destructor.
scoped_ptr is good - just use it :)

Related

What is the common idiom(s) for resetting the moved object?

In C++ move constructor is required to reset the moved object which to me seems to be a duplication of what the destructor does in most of the cases.
Is it correct that defining a reset-method and using it in both destructor and move-constructor is the best approach? Or maybe there are better ways?
Move constructors typically "steal" the resources held by the argument (e.g. pointers to dynamically-allocated objects, file descriptors, TCP sockets, I/O streams, running threads, etc.) rather than make copies of them, and leave the argument in some valid but otherwise indeterminate state. For some types, such as std::unique_ptr, the moved-from state is fully specified.
"Stolen" resources should not be released as this will usually lead to errors. For example, a move constructor which "steals" a pointer has to ensure that the destructor of the moved-from object won't delete the pointer. Otherwise, there will be a double-free. A common way of implementing this is to reset the moved-from pointer to nullptr.
Here is an example:
struct Pointer {
int *ptr;
// obtain a ptr resource which we will manage
Pointer(int* ptr) : ptr{ptr} {}
// steal another object's ptr resource, assign it to nullptr
Pointer(Pointer &&moveOf) : ptr{moveOf.ptr} {
moveOf.ptr = nullptr;
}
// make sure that we don't delete a stolen ptr
~Pointer() {
if (ptr != nullptr) {
delete ptr;
}
}
};
Is it correct that defining a reset-method and using it in both destructor and move-constructor is the best approach? Or maybe there are better ways?
This depends on the resource which is managed, but typically the destructor and move-constructor do different things. The move constructor steals the resource, the destructor frees a resource if it hasn't been stolen.
In C++ move constructor is required to reset the moved object which to me seems to be a duplication of what the destructor does in most of the cases.
You are right that there often is duplication of work. This is because C++ does not have destructive move semantics, so the destructor still gets called separately, even when an object has been moved from. In the example I have shown, ~Pointer() still needs to get called, even after a move. This comes with the runtime cost of checking whether ptr == nullptr. An example of a language with destructive move semantics would be Rust.
Related Posts:
Why does C++ move semantics leave the source constructed?
How does Rust provide move semantics?
How to define a move constructor?
is required to reset the moved object which to me seems to be a duplication of what the destructor does in most of the cases.
It seems to me that you misunderstand what a destructor is used for in most cases.
The purpose of the "reset" (as you call it) in move is to set the state of the object so that it satisfies the internal pre-conditions of the destructor (more generally, any class invariant). If the constructor didn't do that, then the object couldn't be destroyed, which would be against conventions and good practices and would likely lead to mistakes.
In many cases, the destructor cannot possibly do this same "reset". For example, there is no way to distinguish an invalid pointer from a valid pointer. This is why the move constructor of a smart pointer resets the pointer to null.
Is it correct that defining a reset-method and using it in both destructor and move-constructor is the best approach?
It is unclear when this could be useful. Doesn't seem typical.

Why can't classes with a destructor be memcpy'ed

The rules of C++ say that it's legal and will work to copy an object or a POD type using memcpy.
They further say that a POD can't have a (non-trivial) destructor. Why is this and why would the mere addition of a destructor change the class in such a way that using memcpy would not work?
// Perfectly fine to copy using memcpy
struct data
{
int something;
float thing;
};
// Not allowed to copy using memcpy
int var;
struct data
{
int something;
float thing;
~data() { var = 1; }
};
Why would simply adding the destructor make it impossible to memcpy the struct's data? I can't imagine that this would require altering the data layout in any way.
I'm not interested in being told don't do this, I have no intention to do so... I understand I can't do this because "the standard says so" but I'm wondering what the reason the standard says so is as it doesn't seem a necessary restriction to me and want to understand the reasons.
EDIT People seem to be misunderstanding my question. I'm not asking if it's a good idea or not to use memcpy. I'm asking what is the reasoning behind making it illegal if there is a non-trivial destructor. I can't see what difference it makes and want to understand why this restriction exists. Most of the reasons I've been given about it being a bad idea apply just as much if there is a destructor or not.
In layman's terms:
Why would simply adding the destructor make it impossible to memcpy the struct's data?
It doesn't make it impossible, just illegal.
I can't imagine that this would require altering the data layout in any way.
Probably won't, but it's allowed to. Because the class is no longer a POD (i.e. a c struct) it's now a c++ class.
Classes have different rules to PODs. Since we cannot predict how the compiler will go about coding them up, we can no longer reason about the outcome of memcpy.
Non-trivial destructors typically reverse some non-trivial action performed in a constructor (or other member functions) that affect the object state.
memcpy() copies the bits that make up the object. If the behavior of a constructor would give a different set of bits, then the destructor on that object will try to reverse some action that has not actually occurred.
A typical example is a class who's constructors allocate some resource (e.g. memory), other member functions ensure that resource remains in a sane state, and the destructor releases that resource. Copying such an object using memcpy() will copy the handle of that resource, rather than creating a new instance of that resource for the copied object [which is what the copy constructor of such an object typically does]. The destructor - eventually - will be invoked for both the original and copied objects, and the resource will be released twice. For memory (e.g. allocated using C's malloc() or C++'s operator new) releasing twice gives undefined behaviour. For other resources (file handles, mutexes, other system resources) the result varies, but - on must systems - it is generally inadvisable to deallocate a single something twice.
The other problem is that a class may have base classes, or have members, that themselves have non-trivial constructors and destructors. Even if the class itself has a constructor which does nothing, destroying an object invokes destructors of all members and bases. Copying such an object using memcpy() affects those base classes or members in the way I describe above.
Only objects which are trivially copyable can be copied using memcpy. A class with non-trivial destructor is not trivially copyable.
Suppose for an example, your class has a pointer as one of its member. You allocate space for that pointer in the constructor of the class. Now, you can do a variety of things in the non-trivial destructor like deleting the space you allocated. By memcpy you'll be copying the entire structure bit by bit. So two instances will be trying to delete the same pointer when their destructors are called.
This is because memcpy provides a shallow copy and if you have a non trivial dtor it is probably because your object is the owner of some resource, then a shallow copy would not provide you the right copy semantic (duplicate the ownership). Think about some structure with a pointer to something inside, the dtor should (probably) free the resource when the struct disappear, but a shallow copy will let you with a dangling pointer.
The problem is usually that when you have a destructor which does something, you also should have a copy constructor/assignment operator (look up "Rule of 3" for this).
When you memcpy, you will skip these copy operation and this can have some consequences.
E.g. you have a pointer to an object and delete it in the constructor. You then should also specify a copy operation so you copy the pointer/object there too. If you use memcpy instead you have 2 pointers to the same instance and the second destruction would cause an error.
The compilers cannot know what you do in your destructors and if special behavior is needed so it's pessimistic and is seen as a non-POD type anymore. (even if you do nothing in the destructor).
A similar thing happens with the generation of move-assignment/move-constructors when you declare a destructor in a class in c++11.
The problem arises when memory is owned by the class: you should not memcpy a class that owns memory (even if it has no destructor) take for instance:
https://ideone.com/46gFzw
#include <iostream>
#include <memory>
#include <cstring>
struct A
{
std::unique_ptr<int> up_myInt;
A(int val)
:
up_myInt(std::make_unique<int>(val))
{}
};
int main()
{
A a(1);
{
A b(2);
memcpy(&a, &b, sizeof(A));
std::cout << *a.up_myInt << std::endl;
//b gets deleted, and the memory b.up_myInt points to is gone
}
std::cout << *a.up_myInt << std::endl;
return 0;
}
which results in
stdout
2
0
stderr
*** Error in `./prog': double free or corruption (fasttop): 0x08433a20 ***
As b goes out of scope, the data it owned is deleted, a points to the same data, hence fun times (same happens if your class contains basically any other stl container so never ever memcpy an stl containter either.)

Why is raw pointer to shared_ptr construction allowed in all cases?

I was reading Top 10 dumb mistakes to avoid with C++11 smart pointer.
Number #5 reads:
Mistake # 5 : Not assigning an object(raw pointer) to a shared_ptr as
soon as it is created !
int main()
{
Aircraft* myAircraft = new Aircraft("F-16");
shared_ptr<aircraft> pAircraft(myAircraft);
...
shared_ptr<aircraft> p2(myAircraft);
// will do a double delete and possibly crash
}
and the recommendation is something like:
Use make_shared or new and immediately construct the pointer with
it.
Ok, no doubt about it the problem and the recommendation.
However I have a question about the design of shared_ptr.
This is a very easy mistake to make and the whole "safe" design of shared_ptr could be thrown away by very easy-to-detect missuses.
Now the question is, could this be easily been fixed with an alternative design of shared_ptr in which the only constructor from raw pointer would be that from a r-value reference?
template<class T>
struct shared_ptr{
shared_ptr(T*&& t){...basically current implementation...}
shared_ptr(T* t) = delete; // this is to...
shared_ptr(T* const& t) = delete; // ... illustrate the point.
shared_ptr(T*& t) = delete;
...
};
In this way shared_ptr could be only initialized from the result of new or some factory function.
Is this an underexploitation of the C++ language in the library?
or What is the point of having a constructor from raw pointer (l-value) reference if this is going to be most likely a misuse?
Is this a historical accident? (e.g. shared_ptr was proposed before r-value references were introduced, etc) Backwards compatibility?
(Of course one could say std::shared_ptr<type>(std::move(ptr)); that that is easier to catch and also a work around if this is really necessary.)
Am I missing something?
Pointers are very easy to copy. Even if you restrict to r-value reference you can sill easily make copies (like when you pass a pointer as a function parameter) which will invalidate the safety setup. Moreover you will run into problems in templates where you can easily have T* const or T*& as a type and you get type mismatches.
So you are proposing to create more restrictions without significant safety gains, which is likely why it was not in the standard to begin with.
The point of make_shared is to atomize the construction of a shared pointer. Say you have f(shared_ptr<int>(new int(5)), throw_some_exception()). The order of parameter invokation is not guaranteed by the standard. The compiler is allowed to create a new int, run throw_some_exception and then construct the shared_ptr which means that you could leak the int (if throw_some_exception actually throws an exception). make_shared just creates the object and the shared pointer inside itself, which doesn't allow the compiler to change the order, so it becomes safe.
I do not have any special insight into the design of shared_ptr, but I think the most likely explanation is that the timelines involved made this impossible:
The shared_ptr was introduced at the same time as rvalue-references, in C++11. The shared_ptr already had a working reference implementation in boost, so it could be expected to be added to standard libraries relatively quickly.
If the constructor for shared_ptr had only supported construction from rvalue references, it would have been unusable until the compiler had also implemented support for rvalue references.
And at that time, compiler and standards development was much more asynchronous, so it could have taken years until all compiler had implemented support, if at all. (export templates were still fresh on peoples minds in 2011)
Additionally, I assume the standards committee would have felt uncomfortable standardizing an API that did not have a reference implementation, and could not even get one until after the standard was published.
There's a number of cases in which you may not be able to call make_shared(). For example, your code may not be responsible for allocating and constructing the class in question. The following paradigm (private constructors + factory functions) is used in some C++ code bases for a variety of reasons:
struct A {
private:
A();
};
A* A_factory();
In this case, if you wanted to stick the A* you get from A_factory() into a shared_ptr<>, you'd have to use the constructor which takes a raw pointer instead of make_shared().
Off the top of my head, some other examples:
You want to get aligned memory for your type using posix_memalign() and then store it in a shared_ptr<> with a custom deleter that calls free() (this use case will go away soon when we add aligned allocation to the language!).
You want to stick a pointer to a memory-mapped region created with mmap() into a shared_ptr<> with a custom deleter that calls munmap() (this use case will go away when we get a standardized facility for shmem, something I'm hoping to work on in the next few months).
You want to stick a pointer allocated by into a shared_ptr<> with a custom deleter.

Which non-shared Smart Pointer for class member variables

When I have a class that contains pointers as member variables what type of smart pointer should they have if I want don't want to use plain pointers? They do not need to be shared (so no shared_ptr necessary). scoped_ptr won't work since I often need to build the objects outside of the initialization list.
Or is it maybe common practice to use a scoped_ptr during the creation when something can still fail (exceptions thrown etc.) and afterwards assign them to plain pointers?
If you're just wanting to store member pointers in a smart pointer type class so you can't/won't forget to delete them, then a standard choice would be auto_ptr. It's in the STL and is easily "reset" with the reset() function when you need to release the current memory allocated to it and replace it with a new object.
You will still want to implement your own copy constructor and assignment operators for the classes which have auto_ptr members. This is due to the fact that auto_ptrs assignment operator transfers ownership of the underlying object so a default assignment operator will not have the effect you want.
Here is what the class might look like:
class X
{
public:
X() :p(new ClassToManage) {}
X(const X &copy)
:p(new ClassToManage(*copy.p))
{
}
X &operator=(const X &rhs)
{
this->p.reset(new ClassToManage(*rhs.p));
}
private:
std::auto_ptr<ClassToManage> p;
};
For all other cases I would suggest boost::shared_ptr. Shared_ptr does do reference counting but you can store them in standard containers which makes them quite useful.
You should ultimately try to rid yourself of using plain pointers for anything which points at allocated memory it's responsible for deleting. If you want to use a plain pointer for accessing or iterating over a plain ole array etc., then that's fine (but ask yourself why you're not using a std::vector), but when you use them to point at something that it is responsible for freeing then you're asking for trouble. My goal when writing code is to have no explicit deletes.
You could use std::auto_ptr, which was available prior to TR1 and therefore your code is not dependant on a compiler supporting TR1-smartpointers.
Normally I use a deep_copy_ptr. Right now I know of loki smart_ptr and axter smart pointer that do this. It allow the pointer class to be automatically copied somewhat like if it was a normal member variable (you don't need to define a special assignment operator/copy constructor).
I think you don't have to specifically initialize it in the initializer list (but like a normal pointer, don't use it if it do not have a valid value, obviously).

C++ - when should I use a pointer member in a class

One of the thing that has been confusing for me while learning C++ (and Direct3D, but that some time ago) is when you should use a pointer member in a class. For example, I can use a non-pointer declaration:
private:
SomeClass instance_;
Or I could use a pointer declaration
private:
Someclass * instance_
And then use new() on it in the constructor.
I understand that if SomeClass could be derived from another class, a COM object or is an ABC then it should be a pointer. Are there any other guidelines that I should be aware of?
A pointer has following advantages:
a) You can do a lazy initialization, that means to init / create the object only short before the first real usage.
b) The design: if you use pointers for members of an external class type, you can place a forward declaration above your class and thus don't need to include the headers of that types in your header - instead of that you include the third party headers in your .cpp - that has the advantage to reduce the compile time and prevents side effects by including too many other headers.
class ExtCamera; // forward declaration to external class type in "ExtCamera.h"
class MyCamera {
public:
MyCamera() : m_pCamera(0) { }
void init(const ExtCamera &cam);
private:
ExtCamera *m_pCamera; // do not use it in inline code inside header!
};
c) A pointer can be deleted anytime - so you have more control about the livetime and can re-create an object - for example in case of a failure.
The advantages of using a pointer are outlined by 3DH: lazy initialization, reduction in header dependencies, and control over the lifetime of the object.
The are also disadvantages. When you have a pointer data member, you probably have to write your own copy constructor and assignment operator, to make sure that a copy of the object is created properly. Of course, you also must remember to delete the object in the destructor. Also, if you add a pointer data member to an existing class, you must remember to update the copy constructor and operator=. In short, having a pointer data member is more work for you.
Another disadvantage is really the flip side of the control over the lifetime of the object pointed to by the pointer. Non-pointer data members are destroyed automagically when the object is destroyed, meaning that you can always be sure that they exist as long as the object exists. With the pointer, you have to check for it being nullptr, meaning also that you have to make sure to set it to nullptr whenever it doesn't point to anything. Having to deal with all this may easily lead to bugs.
Finally, accessing non-pointer members is likely to be faster, because they are contiguous in memory. On the other hand, accessing pointer data member pointing to an object allocated on the heap is likely to cause a cache miss, making it slower.
There is no single answer to your question. You have to look at your design, and decide whether the advantages of pointer data members outweigh the additional headache. If reducing compile time and header dependencies is important, use the pimpl idiom. If your data member may not be necessary for your object in certain cases, use a pointer, and allocate it when needed. If these do not sound like compelling reasons, and you do not want to do extra work, then do not use a pointer.
If lazy initialization and the reduction of header dependencies are important, then you should first consider using a smart pointer, like std::unique_ptr or std::shared_ptr, instead of a raw pointer. Smart pointers save you from many of the headaches of using raw pointers described above.
Of course, there are still caveats. std::unique_ptr cleans up after itself, so you do not need to add or modify the destructor of your class. However, it is non-copiable, so having a unique pointer as a data member makes your class non-copiable as well.
With std::shared_ptr, you do not have to worry about the destructor or copying or assignment. However, the shared pointer incurs a performance penalty for reference counting.
Allocate it on the stack if you can, from the free-store if you have to. There is a similar question here, where you will find all the "why's".
The reason you see lots of pointer usage when it comes to games and stuff is because DirectX is a COM interface, and in honesty, most games programmers from back in the day aren't really C++ programmers, they are C-with-classes programmers, and in C pointer usage is very common.
Another reason to use pointers would be dynamic binding. If you have a base class with a virtual method and some derived classes, you can only get dynamic binding using pointers.