Variables on the stack

I think one very underused feature in C++ today is simply storing objects on the stack. Many developers who have started writing C# or Java are used to always using new to declare a variable and do the same thing when they are writing C++. And when they later learn that you should never write a naked new, they instead start using unique_ptr or shared_ptr to manage the lifetime of their objects. What they are forgetting is that many times is it sufficient to simply store the instance that you are creating on the stack as a solid object, either as a member of a class or in the local function scope.

The standard library does this all the time, you write

never ever

If you are certain what type of object you need and when you need it, then simply put it on the local stack!

For often called methods you will get a performance increase by doing this since the allocation of an object on the free store takes some time (new has to locate a free portion of memory to allocate).

The exceptions where you don’t want to allocate the object on the local stack include cases where you may want polymorphic behavior, or the class contains large amounts of data making the object too large for the stack.

Facebookgoogle_pluslinkedinmail

Why you should always use a virtual destructor

Virtual destructors are a must when you can delete an object through a pointer to a base class. Let me explain.

Say that you have a simple base class:

and a class deriving from the BaseClass with the addition of a resource which is supposed to be managed using RAII:

now what happens when you use this class:

since the base class doesn’t have a virtual destructor and ‘obj’ is pointing to a BaseClass, not to a DerivedClass, then the destructor of BaseClass is going to be called, but not the destructor of DerivedClass!! This means that the managed resource in DerivedClass is not going to be deleted properly when the object is deleted and thus we have a memory leak!

If instead the BaseClass would have a virtual destructor, like this:

then the constructors would be called in both the base class and the derived class and all contents will be correctly released.

Facebookgoogle_pluslinkedinmail

Shared pointer – std::shared_ptr

With C++11 came a new smart pointer class, std::shared_ptr.

Copyable

The shared pointer is allocated on the stack, exactly like the std::unique_ptr, but unlike the unique pointer is it possible to copy the shared pointer. Just like the unique_ptr will the contents which the smart pointer manages be deleted once the smart pointer goes out of scope. The difference is that the resource will only be deleted when all copies of the shared_ptr have gone out of scope. That is to say that as long as there is at least one handle to the shared memory then the resource will not be cleared.

Performance

The behavior of the std::shared_ptr is in practice implemented through reference counting, creating a new copy of a std::shared_ptr increases a counter of the number of live instances and as each copy goes out of scope this counter is decreased one step. When the counter finally reaches zero then the memory is released. This reference counting means that there is a slight overhead with using a shared_ptr compared to using the unique_ptr which doesn’t have this overhead.

std::weak_ptr

There is also one danger with the shared_ptr, it is possible to create dependency chains where two objects references each other through a shared_ptr and none of the two objects will ever be cleared because there is always one reference to each (by the other object). This “bug” can be resolve by using the third smart pointer introduced in C++11, the std::weak_ptr. A weak pointer is like a copy of a shared_ptr but creating it does not increase the reference count. Therefore, when the object is only reference by weak pointers then the memory will be deleted. The weak pointer can be converted into a std::shared_ptr (which you should do before trying to use it) and if the memory referenced to by the weak_ptr has already been released then you will get an empty shared_ptr back.

Creating – std::make_shared

You create instances of shared_ptr using the helper method std::make_shared. You can of course fill in the contents of the shared pointer yourself but the make_shared method is more efficient (one memory operation less than if you do it yourself) and has the advantage that if the constructor of the object throws an exception then the std::make_shared will make sure that no memory leak occurs.

 

Facebookgoogle_pluslinkedinmail

std::map : The C++ dictionary class

std::map is the C++ standard library implementation of  a dictionary. It contains key-value pairs where the keys are all unique and the key values are used to find the associated values, much like a real-world dictionary. The map is, just like most of the standard library, implemented using templates and the types of the keys and the values are given when you create the map. Some examples of maps:

Each element of the map is of the type std::map<K, V>::value_type which is just a redefinition of std::pair<const K, V>.

Getting one element

To get the value associated with a specific key, use the bracket operator ([]). This operator will create the key-value pair if it doesn’t exist already.

Checking if a key exists in map

There are two ways to check if a key exists in a map.

  1. Using the function std::map::count(). This returns the number of keys which matches the queried key, and since all keys in the std::map are unique can this only be zero or one. This is a good way to do it if you just need to see if the key exists and don’t need to do anything with the map.
  2. Using the function std::map::find(). This returns an iterator to the found object, or std::map::end() if the object is not found. This is a better choice if you need to update the map, since you will get an iterator to the found key value pair.

Iteration

To iterate over all elements in the dictionary use range-based for:

or much simpler using auto

Notice that it is a good idea to make the variable in the loop a reference since this avoids copying the element and gives better performance. Also if you don’t intend to change the element then you can make this clear by also making it const.

Erasing one element

You can erase one element from the map by using the function erase(…) which takes either an iterator, a key or a two iterators defining a range of values to remove.

 

Facebookgoogle_pluslinkedinmail

std::vector

The std::vector is one of the must useful containers of the standard library. It stores an array of elements on the free store (the heap) one after the other, just like you would get if you allocated the memory using new[]. The std::vector is very handy since it is very versatile and easy to use. Being a part of the standard library it will also manage its memory for you (using RAII) which avoids the memory leak problem. Since the objects are allocated contiguously in memory is this possible to use in combination with old code which expects an array of elements.

Creating

std::vector is always allocated on the stack. It can be allocated using uniform initialization:

or using just the size:

It is possible to add elements to the vector one at a time using push_back;

however, pushing back elements at the end of the vector is not recommended if the vector should hold hundreds of elements or more. When you push_back an element to the end then the underlying array will occasionally be resized by allocating a new array and copying all the elements from the old to the new array and this is a very time consuming process.

Iterating

You can iterate through each of the values in the vector using the new range-based for (C++11):

or using std::for_each and a lambda

Number of Elements

Unlike a dynamically allocated array (allocated using new[]), you don’t have to keep track of the size of the vector. Get the number of elements in the vector by calling the method size()

See also: Converting std::vector to C array and back

Facebookgoogle_pluslinkedinmail

Free store vs Heap

There is much confusion regarding the usage of the words stack, heap and free store. Most developers are using the stack and heap wrongly for C++.

Stack

The stack (actually the call stack) is the memory where all your local variables in a function will be located. The stack is a memory structure where all the function calls, from the start of the current thread, up to the currently executed function are stored together with the memory that they use. The variables which reside on the stack are stored there until the function where they reside returns. Once the method returns then all local (stack) variables will be cleaned up.

Heap

The heap is a legacy from C which should not be used in C++. Objects on the heap are allocated using malloc or calloc and released again using free. You should never use malloc or calloc to allocate an object in C++. This since these calls does not call the constructor of the object, leaving you with allocated memory for an invalid object.

Free Store

The free store is in C++ what the heap was in C. Objects on the free store are allocated using new or new[] and released again using delete or delete[]. Objects allocated using new or new[] are allocated and their constructor is being called once the memory is allocated. Objects destroyed using delete or delete[] have their destructor called before the memory is released again.

Facebookgoogle_pluslinkedinmail

Deleted functions

In C++11 is it possible to remove a function from a class by using the delete specifier. If you try to use a deleted function will give a compiler error.

As an example, the following class is made non-movable by making it impossible to call the move operator and move constructor:

We can also stop anyone from creating instances of a class on the free store (heap)  by deleting the new operator:

Or more compact by using a template

To stop users from calling a method with specific parameters, delete the functions with the not allowed parameters:

 

Facebookgoogle_pluslinkedinmail

Order of evaluation

In standard C++ (and C) must

  1. All of a functions arguments be full evaluated before the function is called.
  2. No function calls may interleave with one another, a prior function call must be fully done before the next can start.
  3. Expressions used as function arguments can be evaluated in any order, also interleaved(!) unless this is prohibited by rule 1 or 2.

This means that in the expression

then expression1 and expression2 must be evaluated before func is called, but we don’t know which of them is evaluated first.

In the more complicated example of

then we know that

  1. expression1 is evaluated before g
  2. expression2 is evaluated before h
  3. both g() and h() are evaluated before f() is called.

However, we don’t know if

  • expression1 or expression2 is evaluated first
  • g() or h() is evaluated first
  • expression1 is fully evaluated before h() is called (!)
Facebookgoogle_pluslinkedinmail