Where I came from
I started developing C++ at university where I had my first contact with programming languages. I always had a computer at home since MS-DOS but I never knew or asked myself about how applications run until I started the university. When I started I found it difficult to think as a computer so my efforts where more oriented to memorize routines. Totally wrong, as you may see.
I’ve always worked with C++ during my university studies but it doesn’t mean that I knew how it works or how to use it properly. In fact, the first year I didn’t learn OOP at all, it was just structural programming to learn about loops, arrays and basic data structures. The main problem: not a single explanation of why we were using it in that way. Time after that I started with OOP, some templates and finally the conjunction of OOP with GUI applications. A total disaster as you will find out.
Nowadays
Thanks to Qt I discovered several years ago the containers, multithreading, basic algorithms and networking. Signals and slots are Qt particular so I’ll talk about them in other posts in the future. Anyway, I still had a problem with C++ basis. About 2 or 3 years ago I discovered that my knowledge in C++ was really limited to 03 version. So I started learning and practising C++11 (in 2015 to say so).
After all this time I’ve decided to re-take the blog I had for Qt and extend it to C++ with all the experiments and things I’ve learned. I think it could be useful to anyone who wants to learn new things while it is the same impasse I was before. That’s why I’ve decided to explain in detail my C++11 favorite features. For that purpose I found really useful the book from Scott Meyers.
My C++11 favorite features
The auto specifier
One of my C++11 favorite features is the addition of auto as specifier of data type. It means that we no longer need to write the exact type of data but it is deduced by the compiler. The first thought that came to my mind when I saw it was “Oh shit! C++ has become a Javascript-like language” (I hate untyped languages). But after a while using it I’m converted: it’s powerful, it keeps things organized and it avoids errors!
Another case is when we have large data types and we need to write them several times, it makes the code less readable.
The auto word is also useful to avoid automatic cast. Some times we want to just need float precision or even the integer part of number instead of a double. In that case is better to cast it explicitly so another developer will see it easily:
It’s also important to be aware of the return type of a method or function. A common mistake is to cast the size of a vector into an integer or even a unsigned int. We must know that the return of size() method of vector is size_type and even it is supposed to be unsigned it doesn’t mean that is an unsigned int. In Windows 32-bits both size_type and unsigned int have the same size (32-bits). But in Windows 64-bits size_type is 64-bits long!
Use delete and default keywords
Here there are two different aspects of a common behavior: the method declaration. By using delete what we are telling to the developer is that this method cannot be used or called from anywhere. It is useful for methods that need to be declared but not implemented neither accessible. Let’s see an example with class constuctors and imagine we don’t want anybody copying our object:
The copy constuctor and the assignment operator are not defined and in theory not visible. Except if you add a friend class to it! In that case we will get a link problem because we do not have the methods defined. But, if we don’t want to define them we could use the delete word that does for us:
A similar thing happens with default keyword. In C++11 we have two new special member functions that C++ is willing to generate on its own. In addition to default constructor, copy constructor, destructor and assign operator we have move constructor and move assignment operator (I’ll talk more about them in further C++11 favorite features posts). Those last methods will be generated if the following three conditions are true:
- No copy operations declared
- No move operations declared
- No destructor declared
So, imagine the following code:
In this particular case we have a move constructor and move assignment operator defined without we explicitly did. So, if we don’t need anything else, or we want not to be generated automatically, we can use default:
In addition, default word tells the compiler to explicitly create the destructor.
Do you use inheritance? Override is your word
When we work with inheritance we find that one of the most common problems is to know if we are using polymorphism or just adding a new method with the same name as the base class. That’s a problem when we declare the variable of a type and then we create it in another. Let’s see in an example:
In this case the code compiles without any problem. The real issue here is that speed() doesn’t return a double because it’s not calling the B class method. We declare our object with type A and because of the method is not virtual, the real construction when we allocate memory doesn’t matter. The method called will come from the declared type.
When we use override, it tells us in compile time wether the method we want to overload is declared private in the base class. If it’s not, the compilation will fail with the error message C3668: “method with override specifier ‘override’ did not override any base class methods”.
In the code above there are two problems solved. The first one is the polymorphism in runtime that is solved by using virtual in the method. The second problem is solved by using override so we avoid any possible undesired behavior if the base class changes in the future.
The scoped enums
One of my C++11 favorite features is the scoped enums. They are simple data types that allow us to use them in the same way than unscoped enums but strongly typed. It means that we can avoid strange behaviors and common mistakes by using the same values from different enums. Let’s see some examples:
There are so many things that are not right…
First of all, we are overriding the white color with a different value. It means that if we want to differentiate we must add the scope (Color or FontColor), but we could forget it! Enum class solves it by making mandatory the scope declaration. In addition we are using an enum type for a comparison against an int what is a bit odd. We can still use it in scoped enums, but we have to explicitly cast to it.
Initialize in header file and use nullptr
Here there are several new nice things. All of them are some of my C++11 favorite features, specially the member initialization in header files.
How many times did we forget to initialize class fields that turn on undefined behavior? How many times we did that in the default constructor but then we forget to do it in one of the many override constructors? Now we can initialize all fields in the header file.
IMHO for pointers to objects the best way to initialize them in the header file is just setting them as nullptr. Otherwise we have to include the dependence and it would slow down the compilation time. It would be different if we must include that declaration: in that case we can allocate the memory on it.
It leads us to the use of nullptr instead of NULL or 0. We can still use those values but we should avoid them since nullptr doesn’t have an integer type as it happens with the other. For that reason some calls could be different in some scopes:
In the code above, the use of NULL calls the constructor with an int what it may not be what we want. The second constructor will call the right constructor since it has not integer type.
In further posts…
I know that I missed some things in my C++11 favorite features, probably the most important. The reason why I did it is because they’re so vast and impacts in so many things that I consider they deserve a specific post for each one. Of course I talking about the use of braces ({}) when creating objects, smart pointers and rvalue references (move semantics and forwarding references). Another reason I choose to explain them in another post is because the extension of this first one would be so huge that nobody would read it. In addition, the smart pointers feature has a similar extension in Qt that I’d like to talk about too.
Finally, another future topic will be the loop management and in Qt and C++. There are several post in the internet and I’d like to put them together in one place. So for the moment these have been my c++11 favorite features!
Leave a Reply