Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

C++ 11: Come Closer

4.88/5 (26 votes)
24 Mar 2012CPOL9 min read 89K   363  
Learn a few of the interesting features in C++11.

Introduction

This article aims to help the experienced C++ user to understand and use some of the interesting enhancements in C++ 11. I will discuss some interesting C++ 11 features, including their availability in Visual Studio 11 Beta and g++.

Background

Very good C++ knowledge is required. Here we will only be discussing new things, which are mostly advanced. It is better to leave this article for later if you are not an expert C++ developer.

Come Closer

auto

The auto keyword allows a variable's type to be infered from a function return. That way you do not have to explicitly specify a type. For example, this code:

int foo() { return 5; }
int j = foo();

can be written as:

int foo() { return 5; } 
auto j = foo(); 

and the compiler automatically treats j as an int.

Big deal you might say. Not so. Guess what happens when you have a typename::user::object::foodump::longlongyum::iterator:

name::user::object::foodump::longlongyum::iterator foo() { return ... } 
name::user::object::foodump::longlongyum::iterator j = foo(); 
for(name::user::object::foodump::longlongyum::iterator x = some.begin() ; x < some.end() ; x++) { ... }

All this is very boring and error-prone to type. Using auto makes it considerably simpler and cleaner:

name::user::object::foodump::longlongyum::iterator foo() { return ... } 
auto j = foo(); 
for(auto x = some.begin() ; x < some.end() ; x++) { ... }

My evaluation: Very helpful. Allows to avoid typos.

Visual C++ 11: Available.

G++: Available.

constexpr

The constexpr keyword allows you to specify a function that always has a constant return value. Consider this problem:

int foo() { return 15; }
int j[foo()];

Compiler error. The compiler can't know whether foo() return value is constant.

constexpr int foo() { return 15; } 
int j[foo()];

and the compiler knows that foo() will return a constant.

My evaluation: Not sure. There are many limitations on what a constexpr function can do, plus, in reality, int j[15] is more clean than int j[foo()]. However constexpr can be a hint for the compiler to replace the runtime calculation with compile time calculation - although I 've yet to find a practical example.

Visual C++ 11: Not available.

G++: Available.

Explicit override,final,delete and default

These modifiers allow you to be explicit in member functions:

  • override tells the compiler that a function must override a parent class function
  • final tells the compiler that a function must not be overriden by a descentant class functio
  • default tells the compiler to explicitly generate the default constructor
  • delete tells the compiler that a member of a class must not be called.

override is useful if you want to override a parent function, but accidentally change the function signature, so a second function is generated instead:

class a
  {
  public:
   virtual void foo(int) {...}
  };
class b : public a
  { 
  public:
   virtual void foo() override; // Compiler error. void foo() has not replaced void foo(int)
  }

Here the programmer indents to override a::foo() with b::foo(), but without the override indication a new virtual function is created instead, because the programmer forgot that the original foo() takes an int as a parameter.

final is useful if you want to ensure that a function will never be overriden:

class a
  {
  public:
   virtual void foo(int) final {...}
  };
class b : public a
  { 
  public:
   virtual void foo(int) {}; // Compiler error. void foo(int) is final.
  }

default allows the programmer to tell the compiler that a default constructor should be generated automatically, although there might be other constructors:

class a 
  {
  public:
   a() = default;
   a(int) { ... }
  };

delete allows the programmer to explicity restrict calling to a member, such as a function that would be called due to unwanted casting or a copy constructor:

class a
  {
  public:
   a(const a&) = delete;
   void x(int) = delete;
   void x(float); 
  };

Here, the class copy constructor can't be called, and a call to a::x() must explicitly pass a floating point number (e.g. you can't call x(0)).

My evaluation: Useful. It helps to avoid uneccessary errors.

Visual C++ 11: Not available.

extern template

The keyword extern in a template tells the compiler not to instantiate the template:

template <typename X> class a
  {
  public:
   void test(X); 
  };
template class a<int>; // C++ 03 instantiation
extern template class a<int> // C++ 11 won't instantiate.

C++ 11 won't instantiate the "a", but a will be visible to the current compilation unit.

My evaluation: Useful. It helps to avoid uneccessary instantiations in multiple cpp files.

Visual C++ 11: Not available.

Hash tables

C++ 11 has unordered associative containers, called hash tables. These containers use hashing functions to store elements.

void test_hash() 
	{
	unordered_map<string,int> days(7);
	const char* str[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
	for(int i = 0 ; i < 7 ; i++)
	   days[str[i]] = i;
	auto j = days["Wed"]; // j = 3;
	}

My evaluation: Useful if you need it.

Visual C++ 11: Available.

G++: Available.

Initializer lists

At last, one thing that was missing from C++. The ability to initialize non POD objects with {}. For example, this works:

int j[5] = {1,2,3,4,5};

but this, doesn't:

vector<int> j = {1,2,3,4,5}; 

One had to assign the values in a bothersome way, using a for loop for example. C++ 11 allows a special template called initializer_list that can get its value with { }, and this can be used as a member argument in any function, constructor or not:template <typename X> class A

template <typename X> class A
	{
	public:
		A(int x);
		A(std::initializer_list<int> y);
		void foo(std::initializer_list<X> list);
	};
A<int> a(5); // construct using A(int);
A<float> b({1,2,3,4,5,6}); // construct using A(std::initializer_list<int> y);
b.foo({0.5f,0.6f}); // call foo with parameters.

My evaluation: Extremely Useful .

Visual C++ 11: Not Available :(.

G++: Available.

Lambda functions

A lambda function is an anonymous function that can be used within another function.

Syntax: [capture][arguments]{body}(<call parameters>)

capture is a list of identifiers that will be used in the body (e.g. the function) outside the function. Any attempt to use an identifier outside a lambda function generates a compiler error if the identifier is not in the capture list.

vector<int> flist(15);
int sum = 0;
for(int i= 0 ; i < 15 ;i++)
	flist[i] = i;
for(int i = 0 ; i < 15 ; [&sum](int x) { sum += x;}(flist[i++]));
// sum = 105.

[&sum](int x) { sum += x;} is the lambda function. It captures the "sum" outside variable by reference and adds to it the "x" passed as an argument. It is immediatelly called with flist[i] within the for loop.

You do not need to call it immediately:

auto f = [] (int x, int y) { return x + y; };
int j = f(5,6); // j = 11;

My evaluation: Useful, but be careful because it can easily lead to difficult-to-maintain code.

Visual C++ 11: Available.

G++: Available.

nullptr

The nullptr constant (of type nullptr_t) allows you to specify a pointer type that must not be implicitly converted from zero.

Consider this problem:

int foo(int x) { ... } 
int foo(char* a) { ... }
foo(NULL);

Calling foo(NULL) will call foo(int), not foo(char*), because NULL is defined as 0.

int foo(int x) { ... }
int foo(char* a) { ... }
foo(nullptr);

Now, foo(char*) will be called. nullptr can be implicitly converted to any other pointer type, but not to any integral int type (except from bool). int j = nullptr generates a compiler error.

My evaluation: Almost Useless. It is very rare that you have overloaded functions that take both integral types and pointers, and if you have, there is (usually) a flaw in your design.

Visual C++ 11: Available.

G++: Available.

Polymorphic Function pointers

These are similar to function pointers, except that they allow implicitly conversion of their arguments. For example:

int foo(int x) { return x + 1;}
typedef int (*foop)(short y);
foop f = foo; // Error. It is int foo(int), not int foo(short);

Using polymorphic pointers allows such conversions to be done:

std::function<bool (int)> foo;
bool f2(short a) { ... }
foo = f2; // Valid. short can be converted to int
bool A = foo(5);

My evaluation: Useful, if you know what you are doing. C++ is strongly typed, weaking that feature can result in troubles.

Visual C++ 11: Not Available.

G++: Available.

Regular Expressions

The functions you might have known from IRegExp are now in the standard header <regex>:

char* str = "<h2>Header</h2>"; 
regex rx("<h(.)>([^<]+)");	
cmatch res;
eegex_search(str, res, rx); // isolate "Header"

Of course, regular expressions is a standalone chapter we can't discuss here. But it's nice to see it as a standard.

My evaluation: Useful, if you need regular expressions.

Visual C++ 11: Available.I 'm sure they use old VB's IRegExp ;)
G++: Available.

sizeof member

In C++ 11, sizeof can be used to take the size of a class member, without a class instance:

class a { 
  public
   int b;
  };
int x = sizeof(a::b); // Valid in C++ 11. In C++ 03 you had to have an instance of a class.

My evaluation: Required.

Visual C++ 11: Not Available.

static assert

The assert keyword can be used in runtime to test an assertion, and the #error preprocessor directive can be used in the preprocessor. The new keyword static_assert can be used for the compiler:

int j = 0;
static_assert(j,"error!"); // Compiler error: compilation failed.

My evaluation: Can be useful, but not very important.

Visual C++ 11: Available.

G++: Available.

String literals

So far you can use "string" and L"string" to use normal and wide strings, respectively. C++ 11 adds the following (very useful) literals:

  • u8"string" to define an UTF-8 string.
  • u"string" for an UTF-16 string.
  • U"string" for an UTF-32 string.
  • R"string" for raw string.

Using R"string" allows you to copy/paste strings from sources without the need to escape special characters, such as \.

char* a1 = "Hello there, you can use the \ and / characters to pass arguments"; // Ugh, probably a bug, we forgot to escape \
char* a2 = R"Hello there, you can use the \ and / characters to pass arguments"; // Fine.

My evaluation: Mandatory, especially the R"string".

Visual C++ 11: Not Available. GRRRR.

G++: Available.

Strong enums

Enums are not typed, for example:

enum test {a = 0,b,c,d,e}; // implementation of the enum and it's size is compiler-dependant
int j = e; // valid. 
bool h = d; // valid. 

Now they can be typed:

enum class test: unsigned long {a = 0,b,c,d,e}; // implementation of the enum now is with unsigned long; Guaranteed size and type.
int j = -1;
if (j < test::c) //warning, comparing signed to unsigned. 

My evaluation: Good.

Visual C++ 11: Not Available.
G++: Available.

Threads

Threading classes (including synchronization stuff like mutex) are added to C++ 11.

void test_thread_func(const char* message)
	{
	// Do something with parameter
	}
void test_thread()
	{
	thread t(bind(test_thread_func,"hi!"));
        t.join();
	}

This will start "test_thread_func" in a separated thread and wait until it's completed with the join() function. There are many other facilities, like mutexes, thread local storage support, atomic operations etc.

My evaluation: Good, although you usually need OS-specific extensions for serious threading models. Fortunately, there's a native_handle() member function which returns the native handle (in Win32, a HANDLE) so you can use it when there is no C++ alternative.

Visual C++ 11: Available.
G++: Not available (I couldn't make it to compile at least).

Unique_Ptr and More Smart Pointers

unique_ptr (new in C++ 11), shared_ptr and weak_ptr are available. unique_ptr extends the (now deprecated) auto_ptr in a way that a pointer can be moved:

unique_ptr<int> p1(new int(100));
unique_ptr<int> p2 = move(p1); // Now p2 owns the pointer.
 
p2.reset(); // memory is freed
p1.reset(); // does nothing.

My evaluation: Good, although you shouldn't rely too much on automatic pointers to get off the hook. It's nice to use an allocator class to avoid new and delete, but don't overdo it because it seems to me that there are too many xxxx_ptr classes already. Do not fall in the trap to rely on the smart pointers to enhance a weakly designed application.

Also, note that many people vote for using smart pointers so that memory can be safely destroyed in case of exception, so you can continue without leaks. Remember what an exception should be: An error from which you are 99% not supposed to continue normally. Do not use exceptions instead of if or switch. Do not throw exceptions on errors like invalid password, file not found. Do not catch a "not enough memory" exception. Your code has a flaw already, or windows is terribly unstable!

Visual C++ 11: Available.

G++: Available.

Unrestricted unions

Unrestricted unions allow more freedom on what can be a union and what cannot:

class A
   {
   int b;
   int c;
   A() { b =5; c = 4;}
   };
union B
   {
   int j; 
   A a; // Invalid in C++ 03: A has a non trivial constructor. Valid in C++ 11:
   };

My evaluation: Dangerous. Unions are mostly implemented for lower-level functions like C bit twiddling, assembly stuff etc. They should be very restricted.

Visual C++ 11: Not Available.

Variable Alignment

Till now you could use compiler-specific #pragmas to specify alignment. C++ 11 alows the alignas keyword:

alignas(double) int d[8];  // d contains 8 integers, but it's size is enough to contain 8 doubles also.

In addition, the alignof operator returns the alignment of the identifier, e.g. int j = alignof(d) will return sizeof(double).

My evaluation: Useful.

Visual C++ 11: Not Available.
G++: Not Available.

Variadic Templates

The last entry in our article discusses variadic templates. Those are templates which can take any number and any type of arguments:

template <typename ...T> void foo(T...args)

This allows for type-safe implementations of functions like printf. The example below checks the size of the arguments and calls func1() with the appropriate parameters:

void func1(int a1, int a2, int a3)
 { int j = a1 + a2 + a3;} 
template<class...T> int funcV(A...args)
 {      	
 int size = sizeof...(A);
 if (size == 0) func1(1,2,3);
 if (size == 1) func1(1,2,args...);
 if (size == 2) func1(1,args...);
 if (size == 3) func1(args...);
 }
int main()
 {
 funcV(0);
 funcV(0,1,2);
 funcV(5,3);
 funcV("hello"); // error, func1 does not accept a char*.
 }

Since the "args" are not readily available to the function (because their type and their size is unknown), they are usually called recursively.

My evaluation: Useful, but they can really easily lead to incomprehensible code. Use with caution.

Visual C++ 11: Not Available.

G++: Not Available.

Code

The attached C11.cpp contains samples for all the Visual C++ 11 Beta and G++ available C++ 11 stuff. In case you find more supported features and/or errors, do notify me!

Have fun!

History

  • 24 - 03 - 2012 : Added G++ support
  • 11 - 03 - 2012 : First Release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)