Ruminations on C++11

///////////////////////////////////////////////////////////////////////////

// Preface

//////////

//

// This is a blog about the new version of C++, C++11. It has been many years in the

// making and adds lots of new features to the C++ language. Some of those features

// are already supported by commonly used compilers, a description of these features

// follows.

//

// As you can see, this ‘blog’ is a bit unusual. It’s actually a C++ source code file

// annotated with lots of comments. So it can be read on its own, with the code being

// examples of the things being described, or it can be viewed in Visual Studio (VS)

// 2010, built and even executed. With a few minor adjustments pointed out along the

// way, it can also be built using GCC and executed on whatever system that it is

// installed on.

 

/////////////////////////////////////////////////////////////////////////////////////////

// Ignore these, I couldn’t think of anywhere else to put them.

#include “stdafx.h”

#include <vector>

#include <algorithm>

#include <map>

#include <iostream>

/////////////////////////////////////////////////////////////////////////////////////////

// Ruminations on C++11 (the bits currently supported anyway).

//////////////////////////////////////////////////////////////

//

// Of the many new features of C++11, only a subset are available on stable releases of

// the well-used contemporary C++ compilers. I thought that it would be a good exercise

// in understanding these new features to try them out. I decided that I’d try VS2010 on

// Windows 7 and GCC on Ubuntu, as these are easy for me to access and a reasonable

// approximation of other developers environments.

//

// The main differences being there is no support for nullptr in GCC, and no support for

// initialiser lists in VS2010. Of these, the initialiser lists seem the most useful feature, I hope it gets into VS soon.

//

// The features described here are:

//     * static_assert

//     * trailing return types

//     * constructors calling other constructors in the same class

//     * lambda functions

//     * initialiser lists

//     * a fix for the ‘std::map< int, std::vector<int>>’ ‘>>’ problem

//     * ‘auto’ variable declarations

//     * ‘decltype’ variable declarations

//     * rvalue references, move constructors and perfect forwarding

//     * nullptr, improved typing for the null pointer value

//

// I have annotated some C++11 code that shows the new features, this code does not fully

// comply with our coding standards in order for the descriptions to be clearer. This

// blog contains code that compiles with VS2010, the GCC supported C++11 features are

// provided in the comments.

// 1. static_assert

///////////////////

//

// First we have an example of ‘static_assert’, these are compile time assertions. In

// this case, a check is made to ensure that the size of the type used to instantiate the

// object is sufficient. This check occurs at compile time, so the supplied error message

// is displayed as a compile error if the condition is false.

//

template<class T>

class TemplateTest

{

// if the size of the type used to instantiate an object is too small, a compile

// time error is produced.

static_assert( sizeof(T) > 1, “sizeof(T) not > 1!” );

T m_test;

};

// 2. Trailing return type declarations

///////////////////////////////////////

//

// Next up, an example of trailing return types on method declarations.

// If we have a class that defines an enumeration (very handy for code clarity).

class MyEnumClass

{

public:

enum MyHelpfulEnum

{

An,

Enumeration,

That,

Usually,

Helps,

To,

Clarify,

Code

};

MyEnumClass();

MyEnumClass( MyHelpfulEnum initialValue );

// We can declare the method like this, with a trailing return type,

static auto KeepCodeClear() -> MyHelpfulEnum;

// or like this, it makes no difference to the compiler.

//static MyHelpfulEnum KeepCodeClear();

// But I think it is helpful to keep things consistent.

};

// The advantage of this feature comes when declaring the method implementation, as this

// method returns an enumeration defined within the class. Previously you’d have to

// declare the method decorated with lots of scope to help the compiler know what was

// going on (it has enough to contend with without having to deal with this kind of

// thing). Like so,

//

//MyEnumClass::MyHelpfulEnum MyEnumClass::KeepCodeClear()

//

// But now you can declare the method like this.

auto MyEnumClass::KeepCodeClear() -> MyHelpfulEnum

// The ‘->’ is a little different, but less repetition is involved (sort of).

{

// we’ll see more from ‘auto’ later (why keep a keyword for one use when it can

// have three!?)

return Usually;

}

// 3. One constructor calling another

/////////////////////////////////////

//

// Here we have an example of one constructor calling another, I found it annoying that

// this was missing from C++ in the past.

MyEnumClass::MyEnumClass()

{

// this constructor can call another constructor.

MyEnumClass( Helps );

}

MyEnumClass::MyEnumClass( MyHelpfulEnum initialValue )

{

}

// Here are some function prototypes for the nullptr description (something to look

// forward to).

void NullPointerCall( int notAPointerParameter );

void NullPointerCall( int* aPointerParameter );

// 4. Lambda functions

//////////////////////

//

int _tmain(int argc, _TCHAR* argv

 

[])

{

// Next we have an example of a lambda function (familiar to C# developers). I

// have to admit I’m not a fan of these; if it’s a function make it one, at least

// it can be called from other places then. Now I’ve got that rant out of the way

// we can continue!

//

// If we have a list of interest:

std::vector<int> anInterestingList;

// And that list has some elements, in GCC we can use initialiser lists, like

// so…

//std::vector<int> anInterestingList{1,2,3,4}; // so much nicer.

//

// But for VS we cannot, so add some elements the old fashioned way.

anInterestingList.push_back( 1 );

anInterestingList.push_back( 2 ); // boo

anInterestingList.push_back( 3 );

anInterestingList.push_back( 4 ); // hiss

// Declare an accumulator for our demonstration.

int accumulator( 0 );

// From time to time, it is necessary to loop through all the elements in a list

// (not all that often, but it does happen).

std::for_each( anInterestingList.begin(), anInterestingList.end(),

// Below is the lambda function, the start is defined by ‘[‘, the ampersand

// defines the capture list (the variables accessible by the lambda function),

// if the capture list is empty, i.e. there is only ‘&’, all variables in scope

// are available. It seems like good practice to explicitly state what is

// accessible rather than implying everything. If no ‘&’ appears, i.e ‘[]’ is

// used, no variables are captured. There is also, like any other function a

// parameter list.

[&accumulator](int element){ accumulator += element; } );

// the lambda function, accumulates the values in the list.

std::cout << “Accumulator = ” << accumulator << std::endl;

// 5. ‘>>’ in variable declarations

///////////////////////////////////

//

// The next feature is more of a fix than anything else. Allowing ‘>>’ in

// declarations. Of course you could always get around this problem by sub

// classing, (or even using typedef, but that’s not very OO is it?) but if you did

// do this the error message was, well, …confusing (I’ll leave it at that before

// I say something I shouldn’t).

std::map< int, std::vector<int>> lookItWorks;

// It’s better to subclass if you can though. This is not a C++11 feature, but I

// rarely see it in C++ and it seems so obviously OO.

class AListOfInts : public std::vector<int>{};

class AMapOfIntvsInts : public std::map< int, AListOfInts>{};

// Of course if you wish to use the constructors of the base classes this method

// is annoying. If only there was a way…

AMapOfIntvsInts anAsideToProceedings;

// Well C++11 allows the use of ‘using’ to use base class constructors in derived

// classes, which helps this ‘problem’. If they were implemented by VS or GCC

// I’d add an example.

// 6. ‘auto’ types for variable declarations

////////////////////////////////////////////

//

// This very simple extract of code shows another new use of the auto keyword.

// Here you let the compiler automatically deduce the type.

auto autotest( anInterestingList.begin() );

// 7. ‘decltype’ types for variable declarations

////////////////////////////////////////////////

//

// Similar to the ‘auto’ type deduction feature above, this time declaring a type

// that is the same as another type.

decltype(autotest) decltypetest(autotest);

// declare decltypetest as the same type as autotest.

std::cout << “*autotest = ” << *autotest << std::endl;

std::cout << “*decltypetest = ” << *decltypetest << std::endl;

// 8. rvalue references

///////////////////////

//

// As you can only assign lvalues (like variables, objects and other references)

// to references, C++11 introduces rvalue references for the others (like

// temporaries and literals). I’m not going to get into the details here as

// those subjects require whole documents to themselves. So you can have:

int aValue( 9 );

int& myPreferenceIsAReference( aValue );

int& alsoReferingToAValue( myPreferenceIsAReference );

// But you can’t have:

// MyEnumClass::MyHelpfulEnum& isTheCodeClear( MyEnumClass::KeepCodeClear() );

// as the return from MyEnumClass::KeepCodeClear() is a temporary variable.

//

// In C++11 using rvalue references you can:

MyEnumClass::MyHelpfulEnum&& isTheCodeClear( MyEnumClass::KeepCodeClear() );

if ( isTheCodeClear == MyEnumClass::Usually )

{

std::cout << “isTheCodeClear == MyEnumClass::Usually, must do better!”

<< std::endl;

}

// You can also do things that seem very strange.

int&& rValueRef = 2;

// assign the rvalue reference to a reference to an rvalue, in this case the

// literal number 2.

++rValueRef;

// Has this blown your mind? We have incremented 2! Surely all that we know and

// love is doomed. It’s ok though, as rValueRef is assigned a reference to a

// temporary variable, this is saving time rather than creating a temporary

// and then copying it to a variable.

std::cout << “rValueRef referencing the literal number 2 = “

<< rValueRef << ” OMG!” << std::endl;

// These two examples show that less copying of values is attained by using rvalue

// references. The C++11 standard libraries and STL have been written to take

// advantage of this to improve performance without requiring users of these

// libraries to do anything different (apparently). There’s lots of talk about

// ‘move semantics’ and ‘perfect forwarding’ which is nice if you like that kind

// of thing, these subjects require blogs of their own.

// In summary, they allow less copying, making copy constructors and equals

// operators more efficient. This in turn helps developers to write logical

// code that is far less likely to cause performance issues.

// 1. (again) static_assert

///////////////////////////

//

// static_assert (for compile time assertions). This time we are using the

// static_assert feature to check the sanity of a constant value against another

// constant. This is especially useful to stop people changing constants to

// erroneous values.

const int someConfigValue = 1;

const int someConfigValueCheck = 2;

// As before in the template example, if the condition is false the compiler

// outputs the error text supplied.

static_assert( someConfigValue < someConfigValueCheck,

“someConfigValue is not less than someConfigValueCheck!” );

TemplateTest<int> inttest;

// This is fine, an int passes the static_cast in TemplateTest.

// TemplateTest<bool> booltest;

// This generates a compile time error due to the static cast in the template

// class defined above.

// 9. nullptr

/////////////

//

// nullptr is more strongly typed than 0 or NULL, which helps make things clearer.

// nullptr is not available on GCC at the time of writing so comment out the rest

// of this example to compile with GCC.

int* nullptrtest( nullptr );

if ( nullptrtest == nullptr )

{

// the pointer is null.

std::cout << “The nullptrtest null pointer is set to nullptr.”

<< std::endl;

}

// If we don’t use nullptr, which function is called for our old null pointer

// values?

NullPointerCall( 0 );

NullPointerCall( NULL );

// If we use nullptr instead things are clearer.

NullPointerCall( nullptr );

// 10. initialiser lists

////////////////////////

//

// This is supported by GCC, but not VS, so I’ve commented it out. Obviously

// initialiser lists can also be used to pass data to methods. I think this is one

// of the more useful features of C++11, if only for reasons of clarity.

//std::map< int, int> myuselessnumbermap{ { 1,1 }, { 2, 2 } };

// There are many other C++11 features that haven’t made it into stable versions

// of either VS or GCC, but now that the standard has been ratified I expect they

// will soon follow. Better enum support, in-class member variable initialisation,

// override control and thread support like thread local storage are all useful

// features, there are many more new features that future compilers will support.

// See http://www2.research.att.com/~bs/C++0xFAQ.html for a description of these

// and the unimplemented C++11 features (aka C++0x, they must’ve been a bit late).

return 0;

// Literals in code!! Just this one time I’ll let myself off (anyway, I’ve broken

// most of our other coding standards along the way).

}

// These are the implementations of the nullptr description function calls.

void NullPointerCall( int notAPointerParameter )

{

std::cout << “So you’d like me to process your integer?” << std::endl;

}

void NullPointerCall( int* aPointerParameter )

{

std::cout << “So you’d like me to process your pointer?” << std::endl;

}

More From The Blog

Do It Right First Time? Or, Fight The Fire Later?

Do It Right First Time? Or, Fight The Fire Later?

Do It Right First Time? Or, Fight The Fire Later?When I was a fledgling engineer, the company I worked for hired a new Technical Director.  I remember it vividly because one of his first presentations, to what was a very large engineering team, made the statement...

Standard[ised] Coding

Standard[ised] Coding

Standard[ised] CodingRecently I was handed a piece of code by a client “for my opinion”. A quick glance at the code and I was horrified! This particular piece of code was destined for a SIL0 subsystem of the safety critical embedded system that we were working on. Had...

To Optimise Or Not To Optimise …

To Optimise Or Not To Optimise …

To Optimise Or Not To Optimise ...Computers today are faster than at any time in history. For instance,  the PC on which this blog is being typed is running a multitude of applications, and yet, this concurrency barely registers as the characters peel their ways...

Test Driven Development: A Silver Bullet?

Test Driven Development: A Silver Bullet?

Test Driven Development: A Silver Bullet?Test Driven Development (TDD) is a software development process that started around the early Noughties and is attributed to Kent Beck. The basic concept with TDD is that a test is written and performed first (obviously fails)...

Ticking The Box – Effective Module Testing

Ticking The Box – Effective Module Testing

Ticking The Box - Effective Module TestingIn the world of software development one of the topics of contention is Module Testing. Some value the approach whilst others see it as worthless. These diametrical opposed views even pervade the world of Safety Critical...