Initialization of variables types has received a face lift with the new version of the C++ standard. Previously trying to initialize a populated list was impossible and you were left writing helper functions to transform array values into other container types, or worse you’d end up with code that looked like this.
vector<int>i;// populate the vectori.push_back(1);i.push_back(2);i.push_back(3);i.push_back(4);
C++11 includes a feature called “Uniform Initialization” which aims to solve this problem. The above code now turns into this.
vector<int>i{1,2,3,4};
Much better. This isn’t where the convenience ends though. Take the following example. Because the person class defines a constructor taking in first_name, last_name and age we are able to use uniform initialization to setup these variables.
// declare the person classclassperson{public:person(void)=default;person(conststring&fn,conststring&ln,constinta):first_name(fn),last_name(ln),age(a){}virtual~person(void)=default;private:stringfirst_name,last_name;intage;};// initialize a personpersonp{"John","Smith",25};// initialize a vector of peoplevector<person>people{{"Mary","Brown",21},{"Joe","Jones",35},p,{"Sally","Green",32}};
The same syntax works with any of the enumerated containers. Using the person class from above, we can make a map of employee records by doing the following.
This is the biggest change (shift anyway) in C++’s thinking with the new standard. This preview of Rvalue references probably isn’t pitched at the novice and a bit of prior knowledge is assumed. You’ll want to know the differences between an Lvalue and an Rvalue, you’ll also want to understand how temporary objects work but most importantly why they’re evil in some scenarios. With all of that information under our belt, I can see that the Rvalue reference came to fruition to resolve the copy problem. Returning a temporary object from a function that you’d use in your program would cause an expensive copy operation, now this is is resolved with move semantics. Rather than that expensive copy operation, the value that’s returned is pilfered to the calling code and the temporary object is left empty, ergo a move occurs. An Rvalue reference is defined in code like so.
person&&p=get_temp_person();
The double ampersand && tells us that it’s an Rvalue reference. We can give our own classes the ability to “move” a value by introducing a move constructor and operator like so.
It happened! It finally happened! NULL has a real identity within the language. Forever I’d used the notion of NULL in my C & C++ to really mean 0 (zero) under the covers.
#define NULL 0
Of course, I’d never defined it myself. It was always done for me in one of the many include files drawn into my program. One of the problems with this particular define is for overloaded methods. If you were to pass NULL in its defined state above, you’d be guessing as to which overload is called.
voiduseptr(float*p){/*...*/}voiduseptr(char*p){/*...*/}// float* or char*??useptr(NULL);
Well, now we have nullptr in C++11. nullptr is castable to any pointer type.
The castability also covers off on boolean expressions, so the following if-trees will still work.
if(!p){cout<<"p was null!";}
Finally, nullptr is of type nullptr_t. If you’re going to find it of use to you to guarantee that a null pointer is going to be passed into a method, you could type your method using the type nullptr_t.
Enums in C/C++ have traditionally just been a pretty face for an integer value. That hasn’t changed so much, but a new breed of enumeration has been added with C++11: enter the enum class. Enum classes have been introduced as a “strongly typed” enum. This gives you type safety in your enums so that you don’t perform comparisons between enum types and if you do you’ll need to explicitly define how the two should be compared. The other major benefit is improved scoping. Enum class values must always mention the enumeration that they belong to in order to be used. Here’s an example of an enum class.
enumclassSuit{HEART,DIAMOND,CLUB,SPADE};
Immediately the only difference that you’ll see here is the addition of the word class. You can still explicitly type and value your enumerations. Here’s the same example above only written more verbosely.
One of the annoyances I’ve always had with C++ was its lack of elegant handling of constructors. You’d always be forced to swallow the bitter pill of an initializer function that each of your constructors would call. It always felt clunky to me. With C++11 introducing Delegating Constructors, this has all gone now. Take this simple person class, for example. No magic going on here, just a straight forward class and is how we’d implement multiple constructors without the use of an initialiser.
classperson{public:/* blank person */person(void):first_name(""),middle_name(""),last_name(""){}/* person with no middle name */person(conststring&fn,conststring&ln):first_name(fn),middle_name(""),last_name(ln){}/* person with full name */person(conststring&fn,conststring&mn,conststring&ln):first_name(fn),middle_name(mn),last_name(ln){}public:stringfirst_name,middle_name,last_name;};
Here we have a person class with three constructors all providing their own implementation of how a person object should initialized. This just isn’t nice for a couple of reasons. The first is violation of the DRY principle, we’re repeating ourselves the whole time which goes hand in hand with the second - each constructor initializes the object in its own way. So, the previous answer to this problem was to implement an initializer function which did this work for us.
classperson{public:/* initializes the fields of the person class */voidinit(conststring&fn,conststring&mn,conststring&ln){this->first_name=fn;this->middle_name=mn;this->last_name=ln;}/* blank person */person(void){this->init("","","");}/* person with no middle name */person(conststring&fn,conststring&ln){this->init(fn,"",ln);}/* person with full name */person(conststring&fn,conststring&mn,conststring&ln){this->init(fn,mn,ln);}public:stringfirst_name,middle_name,last_name;};
This is better. We’ve got one way to initialize our class, we’re not repeating ourselves. Life is good. But now (in C++11), there’s a better way. Here I’ll show you how to re-implement this class using delegating constructors for the most elegant of solutions.
We’ve got our most general case constructor (in this case the construct taking in all three names) actually doing the work. The remaining two constructors then just leverage off the functionality defined in the general case. No re-implementation, no initialization function needed.