Templates vs. Virtual functions

You have probably heard about polymorphism before. Well, there are at least two different kinds of polymorphism in C++. Today, we’re going to talk about run time polymorphism via inheritance and compile time polymorphism via templates. Most people are familiar with polymorphism via inheritance. Typically we encounter it early in our programming career, often via some strange example about animals making various noises. Template polymorphism is not so well loved, but in this blog, we are going to give it a chance!

What is polymorphism anyway?

Polymorphism is type abstraction. We are doing polymorphism, when, we ignore some of the specifics of a given type, and treat it as different type, for example through an interface. The best way to understand it is via examples.

Polymorphism via inheritance

Let’s try our hand at a little subclass polymorphism. We are going to create a very simple base class with a virtual method. We will also create a subclass that inherits form this base class, and overrides our virtual base class method.

class SimpleBaseClass
{
public:
    virtual void DoSomethingFun() 
    {
        // put some fun stuff in here
    }
}

class SimpleSubClass : public SimpleBaseClass
{
public:
    void DoSomethingFun()
    {
        // put some different fun stuff here
    }
}

Now we can provide many different implementation of the DoSomethingFun method in different subclasses, and we can use them like so:

int main()
{
    SimpleBaseClass* polyObject = new SimpleSubClass();
    polyObject->DoSomethingFun();
    return 0;
}

When this all compiles, the compiler will create a special lookup table called a vtable. Then, because this is a virtual method, at run time, when the DoSomethingFun method is called on the polyObject pointer, the vtable will be used to find the implementation in the SimpleSubClass. That was polymorphism!

Polymorphism via templates

We have covered the bread and butter of polymorphism. However, we can achieve the same effect with templates! To do this, we are going to define a templated class, and two different implementation classes:

class FunImplementationClass
{
public:
    FunImplementation()
    {
        // put some fun stuff here
    }
}

class AnotherFunImplementationClass
{
public:
    FunImplementation()
    {
        // put some different fun stuff here
    }
}

template <typename T>
public TemplateBaseClass<T>
{
private:
    T implementation;
public:
    TemplateBaseClass(T implementation) : implementation(implementation)
    {
    }

    void DoSomethingFun()
    {
        implementation.FunImplementation();
    }
}

Now we have created a sort of base class like before. But, instead of defining different implementations in subclasses that inherit from this base class, we define them in classes that we pass in via template type parameters.

And we can use this in a very similar (and slightly more verbose) way to the traditional object oriented approach:

int main()
{
    TemplateBaseClass<FunImplementationClass> polyObject = TemplateBaseClass<FunImplementationClass>(FunImplementation());
    polyObject.DoSomethingFun()
    return 0;
}

This time, the compiler will use our templating to resolve which implementation to use, and it will do this at compile time, not run time.

Why would we even want to use templates like this?

There are some disadvantages to the template approach. The most obvious of which is that template programming is not as well known. If you use it, the other people who read, maintain and extend your code, are less likely to be familiar with this technique. So it will be a lot harder for them!

The other, is that templated code is a lot harder to debug. In particular, if you have ever had a compiler error from templated code, you will recognise the error message gore it produces.

I have also heard that templated code is liable to create very large binaries, as so much extra code is generated by the compiler. However I have never seen this being a problem in real life.

With all that said, why might you sill choose to use the templated version? The main reason is performance. There is a performance penalty associated with run time polymorphism. When the correct method is resolved at run time, it requires a look up in the vtable which adds a small but non-zero performance penalty.

In addition to this, when we use compile time polymorphism, the compiler knows exactly what code path we are going to follow. When we use run time polymorphism, that will only be resolved at run time. This means that the compiler has much greater flexibility to optimise our templated code. This can give us a significant performance boost!

Over doing it with methods in C++

A fun fact about the ‘+’ operator is that it can be applied a lot of different types. We can use it on integers, on doubles, even on strings. For each of these, it does some kind of addition. This is method overloading. There are multiple different version of ‘+’ with different signatures, so we can have an abstract notion of addition that works across different types. The great thing is, we can do this in our own code!

What is Overloading?

Overloading a method is when you have more than one method with the same name but different argument types in a class. Something like

class Greeter {
public:
    std::string say_hello() {
        return "Hello";
    }

    std::string say_hello(std::string name) {
        return "Hello " + name;
    }
}

Given a Greeter object, a call to say_hello with no arguments will call the first method and a call to say_hello with a string argument will call the second method.

So we can make as many methods name say_hello as we want in this class with different parameters. However, we cannot have an overload that differs only in return type, like this

class Greeter {
public:
    std::string say_hello() {
        return "Hello";
    }

    // Compiler error!
    bool say_hello() {
        return true;
    }
}

With this code, if you had a Greeter object, and you call say_hello the compiler wouldn’t know which method you are referring to. This is because a call to the say_hello method, might be part of a larger expression, with more method calls, like so:

f(g(greeter.say_hello()) + 5) * g(a)

when this happens, the compiler works recursively upwards, from the deepest method call to the topmost, resolving the types as it goes. So the compiler uses the return type of a method to resolve the type of the parameters of the method at the next level up. So it always needs to know what the return types are.

Don’t hide your wonderful code!

Suppose now we have a base class and a subclass, like this

class BasicGreeter {
public: 
    std::string say_hello() {
        return "Hello";
    }
}

class PoliteGreeter : BasicGreeter {

}

If you have a PoliteGreeter object, you can call the say_hello method from it’s base class. But, suppose we added a say_hello method to PoliteGreeter itself, like so

class BasicGreeter {
public: 
    std::string say_hello() {
        return "Hello";
    }
}

class PoliteGreeter : BasicGreeter {
public: 
    std::string say_hello() {
        return "Hello there good sir";
    }
}

This will compile happily. But, because both say_hello methods have the same signature, the say_hello method in PoliteGreeter is hiding the say_hello method in BasicGreeter. If we call say_hello from a PoliteGreeter object we will get the PoliteGreeter version of that method, not the BasicGreeter version. However, we can still access the BasicGreeter version of the say_hello method by using the base class name directly, like so

PoliteGreeter greeter;
greeter.BasicGreeter::say_Hello(); // This is the sub class say_hello method!

What happens if we try to overload a base class method in a subclass?

class BasicGreeter {
public: 
    std::string say_hello() {
        return "Hello";
    }
}

class PoliteGreeter : BasicGreeter {
public: 
    std::string say_hello(std::string name) {
        return "Hello there " + name;
    }
}

Bad news, even though they have different signatures, the base class method is still hidden! This is quite counter-intuitive to me. In fact, the compiler could make both methods visible in the PoliteGreeter class. But, the C++ standard does not allow it, for confusing and obscure reasons, that I do not understand.

The good news is that we can still use the previous trick to access the subclass method.

PoliteGreeter greeter;

greeter.say_Hello(); // Compiler error! The BasicGreeter say_hello method is hidden!
greeter.BasicGreeter::say_Hello(); 

We can also add a using statement to the PoliteGreeter class itself, that will make the say_hello method in BasicGreeter visible from a PoliteGreeter object.

class PoliteGreeter : BasicGreeter {
public: 
using BasicGreeter::say_hello;

    std::string say_hello(std::string name) {
        return "Hello there " + name;
    }
}

If we want to call the say_hello method from BasicGreeter inside PoliteGreeter without making it visible outside of the class we can reference the subclass like this:

class PoliteGreeter : BasicGreeter {
public: 
    std::string say_hello(std::string name) {
        return BasicGreeter::say_hello() + name;
    }
}

Follow the arrows

When implementing our smart pointers, unique_ptr and shared_ptr, we glossed over the methods operator* and operator->. Now it’s time to see how they work! Let’s look at operator* first:

T& operator*()
{
    return *internal_pointer;
}

When we dereference one of our smart pointers with *, the above method is called. This dereferences the internal_pointer and returns the result. So with our overload we are reaching through our internal pointer to the underlying object. When you dereference a pointer of type T* you get something of type T, so why is the return type T&? Well, the & here means that we are returning by reference. We do this, because we do not want to copy the underlying object when we return it. Suppose the return type was actually T. Then, when we dereferenced a smart pointer, the object pointed to by the internal pointer would be copied to the point where we dereferenced and we would be accessing the members of the copy not the original.

Now let’s look at the -> operator. We defined it like this:

T* operator->()
{
    return internal_pointer;
}

Notice, now we do not dereference, instead we return the internal pointer directly. Suppose we have a simple class like this:

class SillyClass
{
public:
    void SayHello()
    {
        std::cout << "Hello" << std::endl;
    }
};

and in our main method we have created a unique_ptr to a SillyClass object, and use the -> operator to call it’s SayHello method. Like this:

int main()
{
    unique_ptr<SillyClass> ptr(new SillyClass());
    ptr->SayHello();
}

Normally we think of the operation ptr->SayHello() as being equivalent to (*ptr).SayHello(). However, what it does is slightly more complicated.

The -> operator works recursively. If it is called on a pointer type, it dereferences the pointer and resolves the name you asked for, in this case, SayHello. If it is called on a non pointer type, it calls the operator-> method for that type and continues recursively from there.

So in our case, as ptr is not a pointer type, the method unique_ptr::operator-> is called, and the -> operator is applied to the return value. The return value here is of type SillyClass*, this is a pointer type, so it is dereferenced and it’s method SayHello is resolved.

We can see this recursive strategy working in a, very contrived, example. Suppose we wrote the following classes:

class BottomLevel
{
public:
    void SayHello()
    {
        std::cout << "Hello" << std::endl;
    }
};

class MidLevel
{
private:
    BottomLevel* bottomLevel;    
public:
    MidLevel() : bottomLevel(new BottomLevel())
    {
    }

    BottomLevel* operator->()
    {
        return bottomLevel;
    }
};

class TopLevel
{
private:
    MidLevel midLevel;

public:
    TopLevel() : midLevel()
    {
    }

    MidLevel operator->()
    {
        return midLevel;
    }
};

And then we had a main method like this:

int main()
{
    TopLevel top;
    top->SayHello();
}

Here, top is a non pointer type, so -> calls the operator-> method on the top object. This returns a MidLevel object. Midlevel is also not a pointer, so the operator-> method on that object gets called. That returns a pointer to an object of type BottomLevel. As this is a pointer, it is dereferenced, and the method SayHello on this object is resolved.

In practice you usually can just think of the arrow operator as being equivalent to dereferencing and then resolving the name on the underlying type, but when implementing smart pointers, you need to get this right.

Sharing is fun!

So, we have already seen how unique pointers work. They wrap a raw pointer, they cannot be copied and they delete their internal pointer when the they go out of scope. But sometimes we want to use RAII with our pointers, but we need more than a single copy of them. That’s where shared pointer comes in. A shared pointer is just like a unique pointer, except it can be copied! So we can have multiple shared pointers pointing to the same underlying data.

The really clever thing is that a shared pointer keeps track of how many copies of itself there are. It does this by maintaining a counter of the number of copies, called the reference count. When all of the copies of a given shared pointer have gone out scope, the reference count will be 0 and delete is called on the underlying raw pointer. So even though there are multiple copies of the same shared pointer, we can still be sure that the underlying raw pointer will get deleted. You can (sort of) think of a unique pointer as a shared pointer, with a maximum reference count of 1.

Ok then, let’s look at some code!

template<typename T>
class shared_ptr
{
private:
    T* internal_pointer;
    uint* reference_count;

public:
    shared_ptr(T* internal_pointer) : internal_pointer(internal_pointer)
    {
        reference_count = new uint(1);
    }

    shared_ptr(const shared_ptr& source) : internal_pointer(source.internal_pointer), reference_count(source.reference_count)
    {
        (*reference_count)++;
    }

    shared_ptr<T>& operator=(const shared_ptr& source)
    {
        on_reference_deletion();
        internal_pointer = source.internal_pointer;
        reference_count = source.reference_count;
        (*reference_count)++;
        return *this;
    }

    shared_ptr(shared_ptr&& source) : internal_pointer(source.internal_pointer)
, reference_count(source.reference_count)
    {
        source.reference_count = nullptr;
        source.internal_pointer = nullptr;
    }

    shared_ptr<T>& operator=(shared_ptr&& source)
    {
        on_reference_deletion();
        internal_pointer = source.internal_pointer;
        reference_count = source.reference_count;
        source.internal_pointer = nullptr;
        source.reference_count = nullptr;
        return *this;
    }

    T& operator*()
    {
        return *internal_pointer;
    }

    T* operator->()
    {
        return internal_pointer;
    }

    ~shared_ptr()
    {
        if(reference_count)
        {
            on_reference_deletion();
        }
    }

private:
    void on_reference_deletion()
    {
        (*reference_count)--;
        if(*reference_count == 0)
        {
            delete internal_pointer;
        }
    }
};

This is of course very similar to our implementation of unique_ptr. However, now we have an extra member, a pointer to an unsigned integer called reference_count. This is the counter that keeps track of how many copies of this shared_ptr there are. It is a pointer so that all the distinct copies can share the same counter. In the constructor,

    shared_ptr(T* internal_pointer) : internal_pointer(internal_pointer)
    {
        reference_count = new uint(1);
    }

we are creating the first instance of this shared_ptr so we set the reference counter to 1.

We also have a copy constructor now:

    shared_ptr(const shared_ptr& source) : internal_pointer(source.internal_pointer), reference_count(source.reference_count)
    {
        (*reference_count)++;
    }

In this constructor, we copy the internal_pointer and the reference_count from source. Then, as there is a new copy of this shared_ptr, we increment the the reference counter.

The move constructor is similar to the one in unique_ptr:

    shared_ptr(shared_ptr&& source) : internal_pointer(source.internal_pointer), reference_count(source.reference_count)
    {
        source.reference_count = nullptr;
        source.internal_pointer = nullptr;
    }

First we copy across the internal_pointer and the reference_count. We have moved out of source, so it should no longer have any reference to the underlying data. So we set the two pointers inside of source to nullptr. This means that source can now go out of scope, without effecting the internal_pointer or reference_count. Moving does not increase the number of references, so we don’t need to increment the reference counter here.

The copy constructor and move assignment are a little bit more complicated. An object that is being copy or move assigned, will already have been initialised. That means that it already has a pointer to some data and a reference count. So, before the assignment can happen, it needs to decrement the reference count, and if necessary delete the data pointed to by internal_pointer. This operation is handled by the function on_reference_deletion:

    void on_reference_deletion()
    {
        (*reference_count)--;
        if(*reference_count == 0)
        {
            delete internal_pointer;
        }
    }

So our copy assignment looks like this:

    shared_ptr<T>& operator=(const shared_ptr& source)
    {
        on_reference_deletion();
        internal_pointer = source.internal_pointer;
        reference_count = source.reference_count;
        (*reference_count)++;
        return *this;
    }

First we call on_reference_deletion. Then we copy over the data from the source shared_ptr, both the internal_pointer and the reference_count. Then, as we have made a new copy of the source shared_ptr, we increment the reference count.

Then there is the the move assignment operator:

    shared_ptr<T>& operator=(shared_ptr&& source)
    {
        on_reference_deletion();
        internal_pointer = source.internal_pointer;
        reference_count = source.reference_count;
        source.internal_pointer = nullptr;
        source.reference_count = nullptr;
        return *this;
    }

As before, first we call on_reference_deletion and then we copy across the two internal pointers. Just like in the move constructor, we do not want source to have pointer to our data, so we set both it’s internal pointers to nullptr. Again, as moving does not increase the number of references, we do not have to increment the reference count.

An important thing to note, is that, when we move out of a shared_ptr it is not left in a good state. It’s pointers are both set to nullptr. If we try to access them we will get undefined behaviour. This is what we would expect, when we move, we are transferring ownership, so we don’t expect the source to be usable anymore.

Finally, let’s look at our destructor:

    ~shared_ptr()
    {
        if(reference_count)
        {
            on_reference_deletion();
        }
    }

Here, we hare destroying a shared_ptr, so we call on_reference_deletion. However, it is possible that this a shared_ptr that was moved. So first we check to see that the reference_count is a valid pointer. If it is not, we don’t need to do anything.

The great thing about shared_ptr is that we can keep multiple pointers to the same underlying data, and pass them around without having to worry about freeing that memory. It’s almost like a using a language with a garbage collector, like C# or Java. Indeed, shared pointers are a little bit better than garbage collection. In C# or Java, we know only that the garbage collector will reclaim unused memory at some point after the last reference goes out of scope. However, with shared pointers, the memory is reclaimed exactly when the last reference goes out of scope! Which is much more efficient. The one downside compared to garbage collection is that shared_ptr cannot handle circular references. But, we can just be very careful and not create any of them.

auto_ptr is dead, long live unique_ptr!

We talked a bit about auto_ptr in a previous post. In particular we talked about the problem with copying auto_ptr. The auto_ptr class had a copy constructor and copy assignment. However as it was supposed to represent a single unique pointer, these were not actually copies at all. This would cause issues with algorithms that relied on the ability to make normal copies.

So, when C+11 was introduced, a new feature premiered, move semantics. We’ve talked a lot about move semantics already. A move is like a copy, but, you transfer ownership of a resource rather than copying it. That means that the source of the move, is not necessarily left in it’s original state.

Move semantics are just what was needed to fix auto_ptr, and that is how unique_ptr was born. The code looks something like this:

template<typename T>
class unique_ptr
{
private:
    T* internal_pointer;
public:
    unique_ptr(T* internal_pointer) : internal_pointer(internal_pointer)
    {
    }

    unique_ptr(unique_ptr& rhs) = delete;

    unique_ptr<T>& operator=(unique_ptr& rhs) = delete;

    unique_ptr(unique_ptr&& rhs) : internal_pointer(rhs.internal_pointer)
    {
        rhs.internal_pointer = nullptr;
    }

   unique_ptr<T>& operator=(unique_ptr&& rhs)
   {
      delete internal_pointer;
      internal_pointer = rhs.internal_pointer;
      rhs.internal_pointer = nullptr;
      return *this;
   }

   T& operator*()
   {
       return *internal_pointer;
   }

   T* operator->()
   {
       return internal_pointer;
   }

   ~unique_ptr()
   {
       delete internal_pointer;
    }
};

As you can see, this is very similar to our implementation of auto_ptr. There is one big difference. Instead of fake copies, we are using bona fide moves. Indeed, we don’t want to allow copies at all, so we delete the copy constructor and copy assignment explicitly:

   unique_ptr(unique_ptr& rhs) = delete;

   unique_ptr<T>& operator=(unique_ptr& rhs) = delete;

Now, if someone tries to copy a unique_ptr object, their code will not compile. To allow a unique_ptr object to be passed around, we have implemented a move constructor and move assignment:

   unique_ptr(unique_ptr&& rhs) : internal_pointer(rhs.internal_pointer)
   {
       rhs.internal_pointer = nullptr;
   }

   unique_ptr<T>& operator=(unique_ptr&& rhs)
   {
        delete internal_pointer;
        internal_pointer = rhs.internal_pointer;
        rhs.internal_pointer = nullptr;
        return *this;
   }

These have the same implementations as our copy constructor and copy assignment in auto_ptr. However, the && in the signature of these functions means they will only ever be called for a move, not a copy.

The move constructor and assignment will be used when we are constructor or assigning from an object that the compiler can see is just a temporary object. We can also use std::move to tell the compiler explicitly to move our unique pointer. For example, when we passed an auto_ptr to a function, it would have been copied, but with unique_ptr we can move it, like this:

class SomeClass
{
    // pretend there is some interesting code here
}

template<typename T>
void SomeFunction(unique_ptr<T> ptr)
{
    // imagine we do something with ptr here
}

int main()
{
    unique_ptr<SomeClass> ptr(new SomeClass());
    SomeFunction(std::move(ptr));
}

So we now have a safe way to manage a raw pointer. By using unique_ptr we can be sure that delete will be called for our raw pointer when the scope is unwound, we have a guarantee that the unique_ptr will not be copied, and we can move it when we need to.

The Mystery of the Missing Pointer

What was auto_ptr?

The class auto_ptr added smart pointer functionality to C++. It implemented a simple form of RAII. It did this by wrapping a normal (raw) pointer, and calling delete on the pointer in it’s destructor. So, the typical programmer (whether stubborn or not) could use it to manage a raw pointer, and be sure that delete would be called on the raw pointer when the auto_ptr went out of scope.

The implementation looked a little something like this:

template<typename T>
class auto_ptr 
{
private:
    T* internal_pointer;
public:
    auto_ptr(T* internal_pointer) : internal_pointer(internal_pointer)
    {
    }

    auto_ptr(auto_ptr& rhs) : internal_pointer(rhs.internal_pointer)
    {
        rhs.internal_pointer = nullptr;
    }

    auto_ptr<T>& operator=(auto_ptr& rhs)
    {
        delete internal_pointer;
        internal_pointer = rhs.internal_pointer;
        rhs.internal_pointer = nullptr;
        return *this;
    }

    T& operator*()
    {
        return *internal_pointer;
    }

    T* operator->()
    {
        return internal_pointer;
    }

    ~auto_ptr()
    {
        delete internal_pointer;
    }
}

The overloads for the operators operator* and operator-> allow us to treat an auto_ptr as if it were a raw pointer of type T. We can dereference straight to the members of the object of type T that the internal pointer points to. How this actually works is slightly subtle, but the important point is that it works!

This seems like a pretty useful class. So it might surprise you to learn that auto_ptr was deprecated in C++11 and then removed completely in C++17. Usually, there needs to be a pretty good reason to remove a feature like this. So why was it done?

Well, it turns out, that auto_ptr had a pretty huge flaw. Also a separate new feature was added to C++11 that meant a different, better implementation for this kind of smart pointer could be added.

What Was Wrong with auto_ptr?

An important point to understand is that we can only ever have one auto_ptr for a given raw pointer. Suppose we had two such auto_ptrs, when one of them went out of scope, it would delete the underlying memory, but the other auto_ptr would still have a raw pointer to that memory. Which could cause a use after delete or double delete. Which are both undefined behaviour in C++.

So we can’t really copy a auto_ptr. The copy constructor and assignment for auto_ptr could have been removed. This was done in C++ version before 11 by declaring the methods as private, and not giving an implementation. However, we want to be able to pass the auto_ptr into functions and to return it, which uses copying. So, we do a have a copy constructor and copy assignment. Let’s take a look at them:

    auto_ptr(auto_ptr& rhs) : internal_pointer(rhs.internal_pointer)
    {
        rhs.internal_pointer = nullptr;
    }

    auto_ptr<T>& operator=(auto_ptr& rhs)
    {
        delete internal_pointer;
        internal_pointer = rhs.internal_pointer;
        rhs.internal_pointer = nullptr;
        return *this;
    }

These methods copy the internal pointer of rhs, and then set the value of the internal pointer in rhs to nullptr. In the copy assignment we also have to delete the internal pointer, as the object it points to is going out of scope. Neither of these are a copy in any meaningful sense of the world. When copying something, we would not expect the object we are copying to be modified. We would expect to end up with two identical copies of the original object. What this actually does is transfer ownership of the underlying pointer.

This was a problem. We’ve claimed to implement copy, but have done something entirely different. Imagine a photocopier, that produced a perfect copy of whatever document you fed it, but then shredded the original! This caused a particular problem with the standard containers like vector and standard algorithms like sort. The behaviour of these containers and algorithms relied on a normal non-destructive implementation of copy. It was possible to compile code that used auto_ptr with these containers and algorithms, but the resulting behaviour could be very bad!

What Replaced auto_ptr?

What we were trying to do in the copy constructor and copy assignment in auto_ptr was really a move, not a copy. With C++11 move semantics were built right into the language. This meant that a new type of smart pointer could be added, that managed a raw pointer and moved it rather than copying it. This new smart pointer was called unique_ptr. The standard containers and algorithms were also modified in C++11 to use move semantics, so it is possible to use them with unique_ptr.

Staying Safe in C++

What is Exception Safety?

Exceptions are gross. One of the problems with exceptions is that, as they break out of the normal control flow, they can potentially leave our program in a bad state. How do we avoid this?

Well, we can guarantee that we never throw an exception, either because our code is perfect, or, we catch and smoothly handle all exceptions at the point they are thrown. This is a worthy goal, but might not be entirely practical. So the alternative is to follow the philosophy of exception safety. This is the design philosophy that says that we can throw exceptions, but, when we do, we must leave things in a good state.

There are two different flavours of exception safety, strong exception safety and weak exception safety. Strong exception safety is a guarantee that when an exception is thrown during some operation, the overall state will be back to what it was before the operation started. In other words, our methods are atomic or transactional. Weak exception safety is the guarantee that when we throw an exception we will leave things in a valid state. In particular, both forms of exception safety guarantee that we will not leak any resources.

Usually we manage state via classes, and that is also how we think about exception safety. How we make a class exception safe depends on the state that our class manages, and the functionality it exposes via it’s methods.

An Example of Exception Safety

Here’s an example from a job interview I did recently. Suppose we have two strongly exception safe classes: ResourceManager1 and ResourceManager2. In our code we want to define another class, which we, optimistically, name, SafeCopyingClass, like so:

class SafeCopyingClass
{
private:
   int a;
   ResourceManager1 b;
   ResourceManager2* c;
}

The question is, how can we implement a copy constructor for this class in an exception safe way?

We have to copy three member variables. We know that copying an integer like the member a should not throw. This means that we should leave the copy of a until the very end, that way if something goes wrong with the other two copies, we won’t have to roll it back. So, to start, we are going to have something like this:

SafeCopyingClass(const SafeCopyingClass& other)
{
   /// lots of copying logic that might throw
   a = other.a;
}

Now what about copying the members b and c? Suppose we naively copy the objects b and c as below.

SafeCopyingClass(const& SafeCopyingClass& other)
{
   b = ResourceManager1(other.b);
   c = new ResourceManager2(*other.c);
   a = other.a;
}

If the copying of other.b throws, then we are still in the original state so we can just let the exception escape. However, if that first copy succeeds, and then the copy of the RescourceManager2 object throws, then we are not in the original pre-copy state. Indeed, things are even worse than that, we cannot safely get back to the original state. Anything we do to try and restore the pre-copy state, would involve copying ResourceManager1 objects, which would potentially throw again.

So, instead, we are going to copy the ResourceManager2 object first. We are in luck here, because c is in fact a pointer, which is a primitive type, and, although copying the object it points to could throw, copying the pointer itself should not. This means that, we can split the operation into a copy that may throw but leaves our state unchanged, and an assignment that changes our state but should not throw. Concretely, we first copy the other.c object and store the result in a temporary pointer, and then separately assign value in that temporary point to c.

We do this copy of the underlying ResourceManager2 object first, if this throws, as we have not altered the state of the SafeCopyingClass object, we can let this exception escape. The assignment of the value in other.c to c, alters the state so it should go at the end, after all the code that may throw. So our copy constructor now looks like this:

SafeCopyingClass(const SafeCopyingClass& other)
{
   ResourceManager2* temp_c = new ResourceManager2(*other.c);
   // more copying logic that might throw
   c = temp_c;
   a = other.a;
}

Now we just have to deal with the copying of our ResourceManager1 object b. After creating the temporary pointer for our other.c but before we assign that pointer to c, we are still in the original state, so we can copy b and allow exceptions to escape, at this point, like so:

SafeCopyingClass(const SafeCopyingClass& other)
{
   ResourceManager2* temp_c = new ResourceManager2(*other.c);
   b = ResourceManager1(other.b);
   c = temp_c;
   a = other.a;
}

However, there is still one issue with our code. We have a potential resource leak, and that is not only bad practice, it is not exception safe. Suppose, when we copy the other.b object an exception is thrown. Then control will leave this copy constructor. However we created an object of type ResourceManager2. The pointer temp_c is lost, but the object will live on, so we are leaking resources.

So, if the copy of other.b throws, we need to delete the object pointed to by temp_c. To do this, we wrap the ResourceManager1 copy in a try catch block. Then if an exception is thrown we can clean things up and rethrow the exception. So, here his our finished copy constructor:

SafeCopyingClass(const& SafeCopyingClass other)
{
   ResourceManager2* temp_c = new ResourceManager2(other.c);
   try
   {
      b = ResourceManager1(other.b);
   } 
   catch(...)
   {
      delete temp_c;
      throw; 
   }
   c = temp_c;
   a = other.a;
}

What is the general strategy here? We split our copying into stuff that may throw and stuff that should not throw. We do everything that might throw before everything that will not throw. That makes any potential rollback a lot simpler. When we have a pointers, we should copy the underlying objects first and store the result in temporary pointers. After that, we do the rest of the potentially throwing copies, this is where we have to be aware of potential resource leaks and non trivial rollbacks.

Constructors and Destructors in C++ – Part 3

We’ve talked a lot about how construction and destruction work. Now, finally, it’s time to see how they go wrong. Firstly, let’s say that an object is being constructed and an exception is thrown. In this situation the classes destructor is not called. This, in general, should not be a problem. The only exception throwing code you should have in a constructor is code that manages some resource. And, you should manage at most one resource per class. So if an exception is thrown in your constructor, it means that the resource you are managing has not been setup and so the destructor does not need to be called.

So if we have a class like this:

class Base
{
public:
	Base()
	{
		std::cout << "Base Constructor" << std::endl;
		throw std::exception();
	}

	virtual ~Base()
	{
		std::cout << "Base Destructor" << std::endl;
	}
};

and we run the following main function,

int main()
{
    try
    {
        Base baseObject;
    }
    catch(std::exception& e)
    {
        std::cout << "Exception caught" << std::endl;
    }
    return 0;
}

we will see:

Base Constructor
Exception caught

As you see, no calls to the destructor. Now suppose, with the same main function, we throw an exception from a derived class like so,

class Base
{
public:
	Base()
	{
		std::cout << "Base Constructor" << std::endl;
	}

	virtual ~Base()
	{
		std::cout << "Base Destructor" << std::endl;
	}
};

class Derived : public Base
{
public:
	Derived() : Base()
	{
		std::cout << "Derived Constructor" << std::endl;
		throw std::exception();
	}

	Derived(int i)
	{
		std::cout << "Derived with parameter Constructor" << std::endl;
	}

	virtual ~Derived()
	{
		std::cout << "Derived Destructor" << std::endl;
	}
};

Then we will see:

Base Constructor
Derived Constructor
Base Destructor
Exception caught

The Derived destructor is not called, but the Base Destructor is. This is because by the time the exception is thrown in the Derived class, we have completely the construction of the Base class, so that will need to be destroyed as normal.

Local objects that are constructed within the constructor will be destroyed as normal when an exception is thrown. So, for example code like this:

class Simple
{
public:
	Simple()
	{
		std::cout << "Simple Constructor" << std::endl;
	}

	virtual ~Simple()
	{
		std::cout << "Simple Destructor" << std::endl;
	}
};

class Basic
{
public:
	Basic()
	{
		std::cout << "Basic Constructor" << std::endl;
                Simple simpleObject;
		throw std::exception();
	}

	virtual ~Basic()
	{
		std::cout << "Basic Destructor" << std::endl;
	}
};

when executed via,

int main()
{
	try
	{
		Basic basicObject;
	}
	catch(std::exception& e)
	{
		std::cout << "Exception caught" << std::endl;
	}
	return 0;
}

will produce:

Basic Constructor
Simple Constructor
Simple Destructor
Exception caught

So, as we have seen, you can throw exceptions from the constructor. You cannot however throw an exception from a destructor. Try building the following code,

class Simple
{
public:
	Simple()
	{
		std::cout << "Simple Constructor" << std::endl;
	}

	virtual ~Simple()
	{
		std::cout << "Simple Destructor" << std::endl;
                throw std::exception();
	}
};

You should get a warn telling you that destructors are “noexcept” in C++. If you run this code as before, you will get:

Simple Constructor
Simple Destructor
terminate called after throwing an instance of 'std::exception'
  what():  std::exception
Aborted (core dumped)

C++ will always terminate when an exception like this is thrown in a destructor. The reason is simple. Suppose we throw an exception and then start unwinding the stack. If, when we destroy an object on the stack it’s destructor threw another exception, there is no way to catch both exceptions. We cannot catch one exception and abandon the other, so the program gives up and terminates whenever an exception is thrown in a destructor.

Constructors and Destructors in C++ – Part 2

In our previous post we discussed constructors and destructors for local objects. Now, suppose we have the same hierarchy of classes, Base, Derived and DerivedAgain, and we constructed a DerivedAgain object the heap, like so:

int main()
{
    DerivedAgain* derivedAgainObject = new DerivedAgainObject();
    return 0;
}

When we run this we will see the following,

Base Constructor
Derived Constructor
DerivedAgain Constructor

The constructors were called in the same order as before. However, because our DerivedAgain object was created on the heap the destructor was never called. If we want to destroy our object we must explicitly use delete.

int main()
{
    DerivedAgain* derivedAgainObject = new DerivedAgainObject();
    delete derivedAgainObject;
    return 0;
}

The above will output the following to the command line,

Base Constructor
Derived Constructor 
DerivedAgain Constructor
DerivedAgain Destructor
Derived Destructor
Base Destructor

Let’s consider what happens when we have a pointer of type Derived that points to an object of typed DerivedAgain. Say we run:

Derived* derivedPointer = new DerivedAgain();
delete derivedPointer;
return 0;

When we run this code we will see:

Base Constructor
Derived Constructor
DerivedAgain Constructor
Derived Destructor
Base Destructor

The constructors are the same, because we are creating a DerivedAgain object as before. However, now we are calling delete on a pointer of type Derived. So only the Derived and Base class destructors are called.

We can avoid this problem by making our destructors virtual.

class Base
{
public:
        Base()
        {
                std::cout << "Base Constructor" << std::endl;
        }

        virtual ~Base()
        {
                std::cout << "Base Destructor" << std::endl;
        }
};

class Derived : public Base
{
public:
        Derived() : Base()
        {
                std::cout << "Derived Constructor" << std::endl;
        }

        virtual ~Derived()
        {
                std::cout << "Derived Destructor" << std::endl;
        }
};

class DerivedAgain : public Derived
{
public:
        DerivedAgain() : Derived()
        {
                std::cout << "DerivedAgain Constructor" << std::endl;
        }

        ~DerivedAgain()
        {
                std::cout << "DerivedAgain Destructor" << std::endl;
        }
};

Now when we run,

int main()
{
        Derived* derivedPointer = new DerivedAgain();
        delete derivedPointer;
        return 0;
}

we will see:

Base Constructor
Derived Constructor
DerivedAgain Constructor
DerivedAgain Destructor
Derived Destructor
Base Destructor

Even though we have a pointer of type Derived, because the destructor is virtual, when we call delete, the DerivedAgain destructor gets called. What’s interesting here, is that we always call all the destructors upwards through the type hierarchy, the use of virtual ensures that we start at the right level. For this reason, we should usually make our destructors virtual.

We can even make our destructors pure virtual. However, we will have to give this pure virtual destructor a body. It is a common misconception that a pure virtual function necessarily can’t have a body, this is not true. However pure virtual destructors are probably one of the only examples of when you would want to do it. The only reason we would want to make a destructor pure virtual is that we want to make a class abstract and the destructor is the only method. In my opinion this is a very unlikely to happen, so it’s not something we should really worry about.

In the next post we will have a look at what happens when things go wrong in construction and destruction.

Constructors and Destructors in C++ – Part 1

We’re going to think a little bit about constructing and destroying objects in C++. Let’s say we have three very simple classes, Base, Derived and DerivedAgain.

class Base
{
public:
	Base()
	{
		std::cout << "Base Constructor" << std::endl;
	}

	~Base()
	{
		std::cout << "Base Destructor" << std::endl;
	}
};

class Derived : public Base
{
public:
	Derived()
	{
		std::cout << "Derived Constructor" << std::endl;
	}

	~Derived()
	{
		std::cout << "Derived Destructor" << std::endl;
	}
};

class DerivedAgain : public Derived
{
public:
	DerivedAgain()
	{
		std::cout << "DerivedAgain Constructor" << std::endl;
	}

	~DerivedAgain()
	{
		std::cout << "DerivedAgain Destructor" << std::endl;
	}
};

Now suppose we run the following code,

int main()
{
	DerivedAgain derivedAgainObject;
	return 0;
}

The output will be:

Base Constructor
Derived Constructor 
DerivedAgain Constructor
DerivedAgain Destructor
Derived Destructor
Base Destructor

Why is this? Well, to construct the DerivedAgain object, first we must construct aDerived object and to construct a Derived object, first we must construct a Base object. Similarly, when the object goes out of scope, to destroy it, first the DerivedAgain destructor is called, then the Derived destructor and then the Base Destructor. So, when creating an object we step down through the inheritance hierarchy, and when destroying it we step back up through the hierarchy.

We can call these constructors explicitly. Indeed the above code is exactly quivalent to:

class Base
{
public:
	Base()
	{
		std::cout << "Base Constructor" << std::endl;
	}

	~Base()
	{
		std::cout << "Base Destructor" << std::endl;
	}
};

class Derived : public Base
{
public:
	Derived() : Base()
	{
		std::cout << "Derived Constructor" << std::endl;
	}

	~Derived()
	{
		std::cout << "Derived Destructor" << std::endl;
	}
};

class DerivedAgain : public Derived
{
public:
	DerivedAgain() : Derived()
	{
		std::cout << "DerivedAgain Constructor" << std::endl;
	}

	~DerivedAgain()
	{
		std::cout << "DerivedAgain Destructor" << std::endl;
	}
};

Let’s change things up a little bit, suppose we have the following situation.

class Derived : public Base
{
public:
	Derived()
	{
		std::cout << "Derived Constructor" << std::endl;
	}

	Derived(int i)
	{
		std::cout << "Derived Constructor With Parameter" << std::endl;
	}

	~Derived()
	{
		std::cout << "Derived Destructor" << std::endl;
	}
};

class DerivedAgain : public Derived
{
public:
	DerivedAgain() : Derived(5)
	{
		std::cout << "DerivedAgain Constructor" << std::endl;
	}

	~DerivedAgain()
	{
		std::cout << "DerivedAgain Destructor" << std::endl;
	}
};

Now we are explicitly calling a non-default constructor from the Derived class. All the other implicit calls to default constructors remain the same. When we run the main function as before, we will see:

Base Constructor
Derived Constructor with parameter Constructor
DerivedAgain Constructor
DerivedAgain Destructor
Derived Destructor
Base Destructor

You cannot however do something like this:

class DerivedAgain : public Derived
{
public:
	DerivedAgain() : Base()
	{
		std::cout << "DerivedAgain Constructor" << std::endl;
	}

	~DerivedAgain()
	{
		std::cout << "DerivedAgain Destructor" << std::endl;
	}
};

Here, we are trying to call the Base constructor from the DerivedAgain class. This will not compile, we can only call constructors from the classes that we directly inherit from.

So far we have only looked at constructors and destructors for local objects, that is, without using the new keyword. In part 2, we will look at what happens when we construct and destroy objects dynamically.