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.

 

Facebooklinkedinmail

Using RAII to raise the current thread priority temporarily (Windows specific)

In a recent project I had the need to raise the priority of the currently executing thread for a short period of time while an important I/O operation was being performed (the device which the data was read from didn’t have a buffer to store the data hence the reading thread had to be ready at all times to receive the data). I ended up creating a helper class which uses RAII to manage the priority of the current thread. When the object is created on the local scope the priority of the thread is raised and when the object goes out of scope then the destructor will make sure that the priority of the current thread will go back to its original value.

The class deletes the overload of the operator ‘new’ which makes sure that it is impossible to create the object on the free store.

The code to get the current thread and to change the thread priority is Windows specific but I guess this can quite easily be modified to fit other OS:s as well.

 

 

 

Facebooklinkedinmail

std::array : safe C arrays

The std::array was a new container introduced in C++11. A std::array works in the same way as a plain old C array (like int values[5]) but has the advantage that it will not decay into a plain pointer.

Unlike the vector can an array not be resized once it has been created.

Creating

std::array is always allocated on the stack. It it allocated using uniform initialization:

Iterating

You can iterate through each of the values in the array using range-based for:

or using std::for_each and a lambda

Facebooklinkedinmail

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.

 

Facebooklinkedinmail

Entering a literal value

You can enter a literal value using the bases 10 (of course), 8 (octal), 16 (hexadecimal) or 2 (binary, only in c++14).

  • Decimal: any value not starting with a zero is interpreted as a normal (base 10) value.
  • Octal: any value starting with a zero and followed by any of the digits 0 through 7 is interpreted as a base 8 value.
  • Hexadecimal: any value starting with 0x or 0X (zero and lower or upper case X) and then followed by any valid hexadecimal ‘digit’ (0,1,2,3,4,5,6,7,8,9,A,B,C,D,E and F) is interpreted as a base 16 value.

A suffix can be used on the literal to indicate the type of the literal:

  • No suffix: type is signed integer (int, long int or long long int)
  • U: type is unsigned integer (unsigned int, unsigned long int or unsigned long long int)
  • L: type is long integer (long int or long long int)
  • LU: type is unsigned long integer (unsigned long int or unsigned long long int)
  • LL: type is signed extra long integer (long long int, C++11)
  • LLU: type is unsigned extra long integer (unsigned long long int)

It is allowed to enter lower case suffixes also, but this is discouraged since the lower case l can easily be confused with 1 (one).

C++14

C++14 added the binary literal which is entered by starting a value with the characters 0b (zero and lower case b) or 0B (zero and upper case b):

and the possibility to add digit separators:

The digit separators are single-quote characters and does not change the way the literal value is interpreted. They are use only for make the value easier to read.

Facebooklinkedinmail

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

Facebooklinkedinmail

Unique Pointer – std::unique_ptr

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

This is a great class to use when you need to allocate an object which must have a life time longer than the current local scope. In old C++, this would be done by creating the object on the free store using new. It would then be up to you as a programmer to decide when the object is no longer necessary and then call delete on the pointer. The new unique pointer frees you from remembering when to call delete. The key feature of the unique pointer is that is just that, unique. There can be one and only one pointer to the managed object and no copies can ever be made. If you need a pointer which can be shared between many classes then you should instead go for shared_ptr.

The unique pointer is stored on the local scope and when it goes out of scope then the contents of the pointer will be deleted.

Non copyable

The key feature with the unique pointer is that it is unique, this means that no copies of the unique_ptr can ever be made. This has as a side effect that an object which owns a unique_ptr as a member variable can itself not be copied. If you think about it, then this is actually the same behavior as in old C++ when you instead would create a pointer using new and store the pointer as a member variable in a class. That pointer caused problems when you tried to make copies of the owning object, because who should own (and then also delete) the pointer after the copy was made? The original object or the copy? In practice this made the object not copyable unless you explicitly wrote an copy constructor and copy assignment operator. The difference is that in the old way would the program still compile and run. Modern C++ stops you from doing this, it tries to stop you from shooting yourself in the foot!

 Movable

The unique pointer is on the other hand movable, this means that it is possible to create a unique_ptr inside a function and then return the created pointer. It also means that objects owning a unique pointer will themselves also be movable without you having to do anything.

Make

C++11 introduced the std::make_shared function which made it possible to create a shared_ptr safely and easily. However, the make_unique function wasn’t added until C++14 simply because of an oversight in the review. If your compiler supports C++14 then you can create the unique pointer like this

where the parameters to the constructor of the class are passed in the parenthesis

Facebooklinkedinmail

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.

Facebooklinkedinmail

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:

 

Facebooklinkedinmail