The new C++11 standard, finally finalized (pun intended) contains dozens of features, both in the language and in the libraries. Some of those features are pretty complex (or at least less often used), but some are practically essential, and have been sorely missed (at least by me) since forever. Here’s a quick list of those small, simple, features that I like. it’s sometimes surprising to C# or Java developers that some of these features didn’t exist in C++ prior to C++11 (technically, C++03 or C++98; I’ll refer to this as “classic C++”). I will indicate which version of Visual Studio implements each feature (if at all): VS 2010 or VS 11.
1. nullptr
This is one of those features, that is not really a feature – it’s a necessity. In classic C++, a pointer pointing nowhere is written as the value NULL, which is a macro, typically defined as 0, although it doesn’t have to. This is unfortunate for a number of reasons: first, from a purist standpoint, we need to include some header file to get this definition; a definition for something so basic in a language that uses pointers as much as C++. Sure, this may have come from the C standard, but that’s no excuse. Second, this causes some surprising behavior. Consider this simple function overloads:
- void foo(int x) {
- cout << "foo(int)" << endl;
- }
-
- void foo(const char* s) {
- cout << "foo(const char*)" << endl;
- }
What happens if we make the following call:
foo(NULL);
Which function should execute? I would expect the second one, because NULL is supposed to represent a pointer pointing nowhere, and some compilers define that as (void*)0. But some simply use 0. In Visual Studio, this calls the foo(int) version.
C++11 introduces the nullptr keyword. This really means a null pointer – pointer that points nowhere. Now this code
foo(nullptr);
calls the expected function foo(const char*). Visual Studio 2010 implements this feature.
2. auto
The audo keyword (which always existed, but was redundant and meant a stack-based variable) now means the compiler infers the type of a variable based on its intialization. This feature shortens code, usually making it more readable, especially when templates are concerned. For all you C# developers, It’s roughly equivalent to the C# var keyword. Here are some examples:
- auto x = 5; // avoid
- auto name = "hello"; // avoid as well
- string name2 = "hello";
- auto len = name2.size();
-
- map<int, string> dic;
- dic.insert(make_pair(1, "one"));
- dic.insert(make_pair(5, "five"));
- dic.insert(make_pair(100, "hundred"));
-
- for(auto it = dic.begin(); it != dic.end(); ++it)
- cout << it->second << endl;
-
- auto element = dic.find(5);
- if(element == dic.end())
- cout << "not found" << endl;
- else
- cout << "found: " << element->second << endl;
Line 1 says x is an int. The compiler infers that from the right hand side. (5 is an int. 5.0 is double, etc.). This example is an abuse of the feature, so don’t do it.
The second example (line 2) is a little tricky. What is the actual type of name? is it std::string? Nope. It’s a const char*. Line 3 makes this right. Again, don’t use.
The real power of auto comes in line 11. The type if the variable it is something like map<int, string>::iterator. Really verbose to write and adds nothing of value to the code. I know it’s an iterator: why should I care about the exact type? As an iterator, it must support the operators ++ and * (dereferencing) and that’s all I care about.
Line 14 is similar. the find member function returns a map<int, string>::const_iterator. I don’t need to specify that exact type.
Note that auto does not mean “variant”, “object”, “void*” or any such fluid type. It’s a static type just as if I had specified the entire declaration by hand. This means that statements like:
auto x;
auto y = nullptr;
have no meaning and will not compile. The compiler can’t deduce the types of x or y.
This feature is implemented in VS 2010.
3. enum class
Enums have a “bug” in classic C++. Consider this code fragment:
- enum X {
- A, B, C
- };
-
- enum Y {
- W, A, P
- };
This code does not compile, because in C++, enum values have outer scope. This means A defined by X collides with A defined by Y. This also means that setting a value like the following fails:
X x = A;
The compiler can’t distinguish between the two A’s. Perhaps we can write is like so:
X x = X::A;
This is, unfortunately not part of classic C++, although Visual Studio supports this syntax, but issues a warning, saying it’s a non-standard extension.
How can we solve all this? Here’s one idea:
- namespace X {
- enum {
- A, B, C
- };
- }
-
- namespace Y {
- enum {
- W, A, P
- };
- };
-
- void f() {
- int x = X::A;
- int y = Y::A;
- }
I use an anonymous enum nested inside a namespace. This works, but we lose some type safety. I now have to use an int to represent the enum value. Here’s another option:
- struct X {
- enum {
- A, B, C
- };
- };
-
- struct Y {
- enum {
- W, A, P
- };
- };
This is similar, with the potential benefit of not being able to do a “using namespace” to re-introduce outer scope.
C++11 has a new feature, called enum class, that solves the above problem:
- enum class X {
- A, B, C
- };
-
- enum class Y {
- W, A, P
- };
-
- void f() {
- X x = X::A;
- Y y = Y::A;
- }
Now the code is clear and precise. enum class values don’t have outer scope, so the following would not compile:
X x = B;
This feature is not implemented in VS 2010, but is implemented in VS 11.
4. Class member initialization
In classic C++, only static const integral types can be initialized in a class definition like so:
- class Data {
- static const int Count = 10;
-
- int Value;
- };
There is no way to do the same for the Value member variable. In C++11, we can write:
- class Data {
- static const int Count = 10;
-
- int Value = 6;
- };
This effectively initializes the variable in (all) constructors. This is equivalent to this:
- class Data {
- public:
- Data() : Value(6) {
- }
-
- private:
- static const int Count = 10;
- int Value;
- };
The C++11 feature will include such code in all constructors of the class.
A similar feature allows one constructor to call another (as C# and Java allow).
This feature (surprisingly) is not implemented in VS 2010 nor in VS 11.
5. Lambdas
Lambda functions may not be considered a “simple” feature, but at their simplest, they provide a convenient way to replace functors. “Functors”, or function objects, are objects masquerading as functions. This is essentially a class that overrides the call function operator(). Let’s look at an example using the transform algorithm. First, we can use a simple global function:
- int doTransform(int x) {
- return x * 2;
- }
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- vector<int> v;
- for(int i = 1; i <= 5; i++)
- v.push_back(i);
-
- transform(v.begin(), v.end(), v.begin(), doTransform);
-
- for(auto it = v.begin(); it != v.end(); ++it)
- cout << *it << endl;
-
- return 0;
- }
transform is an templated function, and simply expects an operator() to exist. This is obvious for a global function like doTransform. We can replace that with a functor, that can store state (which a global function can’t):
- struct MyTransform {
- int _factor;
- MyTransform(int factor) : _factor(factor) {
- }
-
- int operator()(int x) {
- return x * _factor;
- }
- };
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- vector<int> v;
- for(int i = 1; i <= 5; i++)
- v.push_back(i);
-
- transform(v.begin(), v.end(), v.begin(), MyTransform(2));
-
- for(auto it = v.begin(); it != v.end(); ++it)
- cout << *it << endl;
-
- return 0;
- }
Now we’re passing an object (functor). In C++11, we can pass a lambda function, which is an anonymous function that is placed inline:
- transform(v.begin(), v.end(), v.begin(), [](int x) {
- return x * 2;
- });
This is really handy. The code is stored “locally”, you don’t have to look around to find the actual function transformation. Lambdas are capable of using outer scope variables, like so:
- int factor = 2;
- transform(v.begin(), v.end(), v.begin(), [=](int x) {
- return x * factor;
- });
The little = sign means “capture by value” (as opposed to an ampersand (&) which means “capture by reference”). Lambdas have other interesting properties, but this is the “simple” part that I’ll tackle here. If you’re familiar with C# lambda expressions, then this should look somewhat familiar.
This feature is supported in VS 2010 and enhanced a bit in VS 11.
For an exhaustive list of C++11 features support in VS 2010 & VS 11, check out this post by the VC++ team.