Recent from talks
Contribute something
Nothing was collected or created yet.
C++11
View on WikipediaThis article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these messages)
|
| C++ language revisions |
|---|
C++11 is a version of a joint technical standard, ISO/IEC 14882, by the International Organization for Standardization (ISO) and International Electrotechnical Commission (IEC), for the C++ programming language. C++11 replaced the prior version of the C++ standard, named C++03,[1] and was later replaced by C++14. The name follows the tradition of naming language versions by the publication year of the specification, though it was formerly named C++0x because it was expected to be published before 2010.[2]
Although one of the design goals was to prefer changes to the libraries over changes to the core language,[3] C++11 does make several additions to the core language. Areas of the core language that were significantly improved include multithreading support, generic programming support, uniform initialization, and performance. Significant changes were also made to the C++ Standard Library, incorporating most of the C++ Technical Report 1 (TR1) libraries, except the library of mathematical special functions.[4]
C++11 was published as ISO/IEC 14882:2011[5] in September 2011 and is available for a fee. The working draft most similar to the published C++11 standard is N3337, dated 16 January 2012;[6] it has only editorial corrections from the C++11 standard.[7]
C++11 was fully supported by Clang 3.3 and later,[8] and by GNU Compiler Collection (GCC) 4.8.1 and later.[9]
Design goals
[edit]The design committee attempted to stick to a number of goals in designing C++11:
- Maintain stability and compatibility with older code
- Prefer introducing new features via the standard library, rather than extending the core language
- Improve C++ to facilitate systems and library design, rather than introduce new features useful only to specific applications
- Increase type safety by providing safer alternatives to earlier unsafe techniques
- Increase performance and the ability to work directly with hardware
- Provide proper solutions for real-world problems
- Make C++ easy to teach and to learn without removing any utility needed by expert programmers
Attention to beginners is considered important, because most computer programmers will always be such, and because many beginners never widen their knowledge, limiting themselves to work in aspects of the language in which they specialize.[2][3]
Extensions to the C++ core language
[edit]One function of the C++ committee is the development of the language core. Areas of the core language that were significantly improved include multithreading support, generic programming support, uniform initialization, and performance.
Core language runtime performance enhancements
[edit]These language features primarily exist to provide some kind of runtime performance benefit, either of memory or of computing speed.[citation needed]
Rvalue references and move constructors
[edit]In C++03 (and before), temporaries (termed "rvalues", as they often lie on the right side of an assignment) were intended to never be modifiable — just as in C — and were considered to be indistinguishable from const T& types; nevertheless, in some cases, temporaries could have been modified, a behavior that was even considered to be a useful loophole.[10] C++11 adds a new non-const reference type called an rvalue reference, identified by T&&. This refers to temporaries that are permitted to be modified after they are initialized, for the purpose of allowing "move semantics".
A chronic performance problem with C++03 is the costly and unneeded deep copies that can happen implicitly when objects are passed by value. To illustrate the issue, consider that an std::vector<T> is, internally, a wrapper around a C-style array with a defined size. If an std::vector<T> temporary is created or returned from a function, it can be stored only by creating a new std::vector<T> and copying all the rvalue's data into it. Then the temporary and all its memory is destroyed. (For simplicity, this discussion neglects the return value optimization.)
In C++11, a move constructor of std::vector<T> that takes an rvalue reference to an std::vector<T> can copy the pointer to the internal C-style array out of the rvalue into the new std::vector<T>, then set the pointer inside the rvalue to null. Since the temporary will never again be used, no code will try to access the null pointer, and because the pointer is null, its memory is not deleted when it goes out of scope. Hence, the operation not only forgoes the expense of a deep copy, but is safe and invisible.
Rvalue references can provide performance benefits to existing code without needing to make any changes outside the standard library. The type of the returned value of a function returning an std::vector<T> temporary does not need to be changed explicitly to std::vector<T> && to invoke the move constructor, as temporaries are considered rvalues automatically. (However, if std::vector<T> is a C++03 version without a move constructor, then the copy constructor will be invoked with a const std::vector<T>&, incurring a significant memory allocation.)
For safety reasons, some restrictions are imposed. A named variable will never be considered to be an rvalue even if it is declared as such. To get an rvalue, the function template std::move() should be used. Rvalue references can also be modified only under certain circumstances, being intended to be used primarily with move constructors.
Due to the nature of the wording of rvalue references, and to some modification to the wording for lvalue references (regular references), rvalue references allow developers to provide perfect function forwarding. When combined with variadic templates, this ability allows for function templates that can perfectly forward arguments to another function that takes those particular arguments. This is most useful for forwarding constructor parameters, to create factory functions that will automatically call the correct constructor for those particular arguments. This is seen in the emplace_back set of the C++ standard library methods.
constexpr – Generalized constant expressions
[edit]C++ has always had the concept of constant expressions. These are expressions such as 3+4 that will always yield the same results, at compile time and at runtime. Constant expressions are optimization opportunities for compilers, and compilers frequently execute them at compile time and hardcode the results in the program. Also, in several places, the C++ specification requires using constant expressions. Defining an array requires a constant expression, and enumerator values must be constant expressions.
However, a constant expression has never been allowed to contain a function call or object constructor. So a piece of code as simple as this is invalid:
int getFive() {
return 5;
}
int someValue[getFive() + 7]; // Create an array of 12 integers. Ill-formed C++
This was not valid in C++03, because getFive() + 7 is not a constant expression. A C++03 compiler has no way of knowing if getFive() actually is constant at runtime. In theory, this function could affect a global variable, call other non-runtime constant functions, etc.
C++11 introduced the keyword constexpr, which allows the user to guarantee that a function or object constructor is a compile-time constant.[11] The above example can be rewritten as follows:
constexpr int getFive() {
return 5;
}
int someValue[getFive() + 7]; // Create an array of 12 integers. Valid C++11
This allows the compiler to understand, and verify, that getFive() is a compile-time constant.
Using constexpr on a function imposes some limits on what that function can do. First, the function must have a non-void return type. Second, the function body cannot declare variables or define new types. Third, the body may contain only declarations, null statements and a single return statement. There must exist argument values such that, after argument substitution, the expression in the return statement produces a constant expression.
Before C++11, the values of variables could be used in constant expressions only if the variables are declared const, have an initializer which is a constant expression, and are of integral or enumeration type. C++11 removes the restriction that the variables must be of integral or enumeration type if they are defined with the constexpr keyword:
constexpr double EARTH_GRAVITATIONAL_ACCELERATION = 9.8f;
constexpr double MOON_GRAVITATIONAL_ACCELERATION = EARTH_GRAVITATIONAL_ACCELERATION / 6.0f;
Such data variables are implicitly const, and must have an initializer which must be a constant expression.
To construct constant expression data values from user-defined types, constructors can also be declared with constexpr. A constexpr constructor's function body can contain only declarations and null statements, and cannot declare variables or define types, as with a constexpr function. There must exist argument values such that, after argument substitution, it initializes the class's members with constant expressions. The destructors for such types must be trivial.
The copy constructor for a type with any constexpr constructors should usually also be defined as a constexpr constructor, to allow objects of the type to be returned by value from a constexpr function. Any member function of a class, such as copy constructors, operator overloads, etc., can be declared as constexpr, so long as they meet the requirements for constexpr functions. This allows the compiler to copy objects at compile time, perform operations on them, etc.
If a constexpr function or constructor is called with arguments which aren't constant expressions, the call behaves as if the function were not constexpr, and the resulting value is not a constant expression. Likewise, if the expression in the return statement of a constexpr function does not evaluate to a constant expression for a given invocation, the result is not a constant expression.
constexpr differs from consteval, introduced in C++20, in that the latter must always produce a compile time constant, while constexpr does not have this restriction.
Modification to the definition of plain old data
[edit]In C++03, a class or struct must follow a number of rules for it to be considered a plain old data (POD) type. Types that fit this definition produce object layouts that are compatible with C, and they could also be initialized statically. The C++03 standard has restrictions on what types are compatible with C or can be statically initialized despite there being no technical reason a compiler couldn't accept the program; if someone were to create a C++03 POD type and add a non-virtual member function, this type would no longer be a POD type, could not be statically initialized, and would be incompatible with C despite no change to the memory layout.
C++11 relaxed several of the POD rules, by dividing the POD concept into two separate concepts: trivial and standard-layout.
A type that is trivial can be statically initialized. It also means that it is valid to copy data around via memcpy, rather than having to use a copy constructor. The lifetime of a trivial type begins when its storage is defined, not when a constructor completes.
A trivial class or struct is defined as one that:
- Has a trivial default constructor. This may use the default constructor syntax (
SomeConstructor() = default;). - Has trivial copy and move constructors, which may use the default syntax.
- Has trivial copy and move assignment operators, which may use the default syntax.
- Has a trivial destructor, which must not be virtual.
Constructors are trivial only if there are no virtual member functions of the class and no virtual base classes. Copy/move operations also require all non-static data members to be trivial.
A type that is standard-layout means that it orders and packs its members in a way that is compatible with C. A class or struct is standard-layout, by definition, provided:
- It has no virtual functions
- It has no virtual base classes
- All its non-static data members have the same access control (public, private, protected)
- All its non-static data members, including any in its base classes, are in the same one class in the hierarchy
- The above rules also apply to all the base classes and to all non-static data members in the class hierarchy
- It has no base classes of the same type as the first defined non-static data member
A class/struct/union is considered POD if it is trivial, standard-layout, and all of its non-static data members and base classes are PODs.
By separating these concepts, it becomes possible to give up one without losing the other. A class with complex move and copy constructors may not be trivial, but it could be standard-layout and thus interoperate with C. Similarly, a class with public and private non-static data members would not be standard-layout, but it could be trivial and thus memcpy-able.
Core language build-time performance enhancements
[edit]Extern template
[edit]In C++03, the compiler must instantiate a template whenever a fully specified template is encountered in a translation unit. If the template is instantiated with the same types in many translation units, this can dramatically increase compile times. There is no way to prevent this in C++03, so C++11 introduced extern template declarations, analogous to extern data declarations.
C++03 has this syntax to oblige the compiler to instantiate a template:
template class std::vector<MyClass>;
C++11 now provides this syntax:
extern template class std::vector<MyClass>;
which tells the compiler not to instantiate the template in this translation unit.
Core language usability enhancements
[edit]These features exist for the primary purpose of making the language easier to use. These can improve type safety, minimize code repetition, make erroneous code less likely, etc.
Initializer lists
[edit]C++03 inherited the initializer-list feature from C. A struct or array is given a list of arguments in braces, in the order of the members' definitions in the struct. These initializer-lists are recursive, so an array of structs or struct containing other structs can use them.
struct FloatAndInt {
float first;
int second;
};
FloatAndInt scalar = {0.43f, 10}; // One Object, with first=0.43f and second=10
FloatAndInt anArray[] = {{13.4f, 3}, {43.28f, 29}, {5.934f, 17}}; // An array of three Objects
This is very useful for static lists, or initializing a struct to some value. C++ also provides constructors to initialize an object, but they are often not as convenient as the initializer list. However, C++03 allows initializer-lists only on structs and classes that conform to the Plain Old Data (POD) definition; C++11 extends initializer-lists, so they can be used for all classes including standard containers like std::vector.
C++11 binds the concept to a template, called std::initializer_list. This allows constructors and other functions to take initializer-lists as parameters. For example:
using std::initializer_list;
class SequenceClass {
public:
SequenceClass(initializer_list<int> list);
};
This allows SequenceClass to be constructed from a sequence of integers, such as:
SequenceClass someSeq = {1, 4, 5, 6};
This constructor is a special kind of constructor, called an initializer-list-constructor. Classes with such a constructor are treated specially during uniform initialization (see below)
The template class std::initializer_list<> is a first-class C++11 standard library type. They can be constructed statically by the C++11 compiler via use of the {} syntax without a type name in contexts where such braces will deduce to an std::initializer_list, or by explicitly specifying the type like std::initializer_list<SomeType>{args} (and so on for other varieties of construction syntax).
The list can be copied once constructed, which is cheap and will act as a copy-by-reference (the class is typically implemented as a pair of begin/end pointers). An std::initializer_list is constant: its members cannot be changed once it is created, and nor can the data in those members be changed (which rules out moving from them, requiring copies into class members, etc.).
Although its construction is specially treated by the compiler, an std::initializer_list is a real type, and so it can be used in other places besides class constructors. Regular functions can take typed std::initializer_lists as arguments. For example:
using std::initializer_list;
void functionName(initializer_list<float> list); // Copying is cheap; see above
functionName({1.0f, -3.45f, -0.4f});
Examples of this in the standard library include the std::min() and std::max() templates taking std::initializer_lists of numeric type.
Standard containers can also be initialized in these ways:
using std::string;
using std::vector;
vector<string> v = { "xyzzy", "plugh", "abracadabra" };
vector<string> v({ "xyzzy", "plugh", "abracadabra" });
vector<string> v{ "xyzzy", "plugh", "abracadabra" }; // see "Uniform initialization" below
Uniform initialization
[edit]C++03 has a number of problems with initializing types. Several ways to do this exist, and some produce different results when interchanged. The traditional constructor syntax, for example, can look like a function declaration, and steps must be taken to ensure that the compiler's most vexing parse rule will not mistake it for such. Only aggregates and POD types can be initialized with aggregate initializers (using SomeType var = {/*stuff*/};).
C++11 provides a syntax that allows for fully uniform type initialization that works on any object. It expands on the initializer list syntax:
struct IntAndFloat1 {
int x;
double y;
};
struct IntAndFloat2 {
private:
int x;
double y;
public:
IntAndFloat(int x, double y):
x{x}, y{y} {}
};
IntAndFloat1 var1{5, 3.2};
IntAndFloat2 var2{2, 4.3};
The initialization of var1 behaves exactly as though it were aggregate-initialization. That is, each data member of an object, in turn, will be copy-initialized with the corresponding value from the initializer-list. Implicit type conversion will be used where needed. If no conversion exists, or only a narrowing conversion exists, the program is ill-formed. The initialization of var2 invokes the constructor.
One can also do this:
using std::string;
struct IdString {
string name;
int identifier;
};
IdString getString() {
return {"foo", 42}; // Note the lack of explicit type.
}
Uniform initialization does not replace constructor syntax, which is still needed at times. If a class has an initializer list constructor (TypeName(initializer_list<SomeType>);), then it takes priority over other forms of construction, provided that the initializer list conforms to the sequence constructor's type. The C++11 version of std::vector has an initializer list constructor for its template type. Thus this code:
std::vector<int> vec{4};
will call the initializer list constructor, not the constructor of std::vector that takes a single size parameter and creates the vector with that size. To access the latter constructor, the user will need to use the standard constructor syntax directly.
Type inference
[edit]In C++03 (and C), to use a variable, its type must be specified explicitly. However, with the advent of template types and template metaprogramming techniques, the type of something, particularly the well-defined return value of a function, may not be easily expressed. Thus, storing intermediates in variables is difficult, possibly needing knowledge of the internals of a given metaprogramming library.
C++11 allows this to be mitigated in two ways. First, the definition of a variable with an explicit initialization can use the auto keyword.[12][13] This creates a variable of the specific type of the initializer:
auto some_strange_callable_type = std::bind(&some_function, _2, _1, some_object);
auto other_variable = 5;
The type of some_strange_callable_type is simply whatever the particular template function override of std::bind returns for those particular arguments. This type is easily determined procedurally by the compiler as part of its semantic analysis duties, but is not easy for the user to determine upon inspection.
The type of other_variable is also well-defined, but it is easier for the user to determine. It is an int, which is the same type as the integer literal.
This use of the keyword auto in C++ re-purposes the semantics of this keyword, which was originally used in the typeless predecessor language B in a related role of denoting an untyped automatic variable definition.
Further, the keyword decltype can be used to determine the type of expression at compile-time. For example:
int some_int;
decltype(some_int) other_integer_variable = 5;
This is more useful in conjunction with auto, since the type of auto variable is known only to the compiler. However, decltype can also be very useful for expressions in code that makes heavy use of operator overloading and specialized types.
auto is also useful for reducing the verbosity of the code. For instance, instead of writing
for (std::vector<int>::const_iterator itr = myvec.cbegin(); itr != myvec.cend(); ++itr)
the programmer can use the shorter
for (auto itr = myvec.cbegin(); itr != myvec.cend(); ++itr)
which can be further compacted since "myvec" implements begin/end iterators:
for (const auto& x : myvec)
This difference grows as the programmer begins to nest containers, though in such cases typedefs are a good way to decrease the amount of code.
The type denoted by decltype can be different from the type deduced by auto.
#include <vector>
using std::vector;
int main() {
const vector<int> v(1);
auto a = v[0]; // a has type int
decltype(v[0]) b = 1; // b has type const int&, the return type of
// std::vector<int>::operator[](size_type) const
auto c = 0; // c has type int
auto d = c; // d has type int
decltype(c) e; // e has type int, the type of the entity named by c
decltype((c)) f = c; // f has type int&, because (c) is an lvalue
decltype(0) g; // g has type int, because 0 is an rvalue
}
Range-based for loop
[edit]C++11 extends the syntax of the for statement to allow for easy iteration over a range of elements:
int my_array[5] = {1, 2, 3, 4, 5};
// double the value of each element in my_array:
for (int& x : my_array) {
x *= 2;
}
// similar but also using type inference for array elements
for (auto& x : my_array) {
x *= 2;
}
This form of for, called the “range-based for”, will iterate over each element in the list. It will work for C-style arrays, initializer lists, and any type that has begin() and end() functions defined for it that return iterators. All the standard library containers that have begin/end pairs will work with the range-based for statement.
Lambda functions and expressions
[edit]C++11 provides the ability to create anonymous functions, called lambda functions.[14] These are defined as follows:
[](int x, int y) -> int {
return x + y;
}
The return type (-> int in this example) can be omitted as long as all return expressions return the same type.
A lambda can optionally be a closure.
Alternative function syntax
[edit]Standard C function declaration syntax was perfectly adequate for the feature set of the C language. As C++ evolved from C, it kept the basic syntax and extended it where needed. However, as C++ grew more complex, it exposed several limits, especially regarding template function declarations. For example, in C++03 this is invalid:
template <class L, class R>
Ret add(const L& lhs, const R& rhs) {
return lhs + rhs; // Ret must be the type of lhs + rhs
}
The type Ret is whatever the addition of types L and R will produce. Even with the aforementioned C++11 functionality of decltype, this is not possible:
// Not valid C++11
template <class L, class R>
decltype(lhs + rhs) add(const L& lhs, const R& rhs) {
return lhs + rhs;
}
This is not valid C++ because lhs and rhs have not yet been defined; they will not be valid identifiers until after the parser has parsed the rest of the function prototype.
To work around this, C++11 introduced a new function declaration syntax, with a trailing-return-type:[15]
template <class L, class R>
auto add(const L& lhs, const R& rhs) -> decltype(lhs + rhs) {
return lhs + rhs;
}
This syntax can be used for more mundane function declarations and definitions:
struct SomeStruct {
auto add(int x, int y) -> int {
return x + y;
}
};
The use of the "auto" keyword in this case is just part of the syntax and does not perform automatic type deduction in C++11. However, starting with C++14, the trailing return type can be removed entirely and the compiler will deduce the return type automatically.[16]
Object construction improvement
[edit]In C++03, constructors of a class are not allowed to call other constructors in an initializer list of that class. Each constructor must construct all of its class members itself or call a common member function, as follows:
class Integer {
private:
int value;
void setValue(int num) {
value = num;
}
public:
Integer(int number) {
setValue(number);
}
Integer() {
setValue(42);
}
};
Constructors for base classes cannot be directly exposed to derived classes; each derived class must implement constructors even if a base class constructor would be appropriate. Non-constant data members of classes cannot be initialized at the site of the declaration of those members. They can be initialized only in a constructor.
C++11 provides solutions to all of these problems.
C++11 allows constructors to call other peer constructors (termed delegation). This allows constructors to utilize another constructor's behavior with a minimum of added code. Delegation has been used in other languages e.g., Java and Objective-C.
This syntax is as follows:
class Integer {
private:
int value;
public:
Integer(int number):
value(number) {}
Integer():
Integer(42) {}
};
In this case, the same effect could have been achieved by making number a default parameter. The new syntax, however, allows the default value (42) to be expressed in the implementation rather than the interface — a benefit to maintainers of library code since default values for function parameters are “baked in” to call sites, whereas constructor delegation allows the value to be changed without recompilation of the code using the library.
This comes with a caveat: C++03 considers an object to be constructed when its constructor finishes executing, but C++11 considers an object constructed once any constructor finishes execution. Since multiple constructors will be allowed to execute, this will mean that each delegating constructor will be executing on a fully constructed object of its own type. Derived class constructors will execute after all delegation in their base classes is complete.
For base-class constructors, C++11 allows a class to specify that base class constructors will be inherited. Thus, the C++11 compiler will generate code to perform the inheritance and the forwarding of the derived class to the base class. This is an all-or-nothing feature: either all of that base class's constructors are forwarded or none of them are. Also, an inherited constructor will be shadowed if it matches the signature of a constructor of the derived class, and restrictions exist for multiple inheritance: class constructors cannot be inherited from two classes that use constructors with the same signature.
The syntax is as follows:
class BaseClass {
public:
BaseClass(int value);
};
class DerivedClass : public BaseClass {
public:
using BaseClass::BaseClass;
};
For member initialization, C++11 allows this syntax:
class Integer {
private:
int value = 5;
public:
Integer() {}
explicit Integer(int value):
value(value) {}
};
Any constructor of the class will initialize value with 5, if the constructor does not override the initialization with its own. So the above empty constructor will initialize value as the class definition states, but the constructor that takes an int will initialize it to the given parameter.
It can also use constructor or uniform initialization, instead of the assignment initialization shown above.
Explicit overrides and final
[edit]In C++03, it is possible to accidentally create a new virtual function, when one intended to override a base class function. For example:
struct Base {
virtual void someFunction(float);
};
struct Derived : public Base {
virtual void someFunction(int);
};
Suppose the Derived::someFunction is intended to replace the base class version. But instead, because it has a different signature, it creates a second virtual function. This is a common problem, particularly when a user goes to modify the base class.
C++11 provides syntax to solve this problem.
struct Base {
virtual void someFunction(float);
};
struct Derived : public Base {
virtual void someFunction(int) override; // ill-formed - doesn't override a base class method
};
The override special identifier means that the compiler will check the base class(es) to see if there is a virtual function with this exact signature. And if there is not, the compiler will indicate an error.
C++11 also adds the ability to prevent inheriting from classes or simply preventing overriding methods in derived classes. This is done with the special identifier final. For example:
struct Base1 final { };
struct Derived1 : public Base1 { }; // ill-formed because the class Base1 has been marked final
struct Base2 {
virtual void f() final;
};
struct Derived2 : public Base2 {
void f(); // ill-formed because the virtual function Base2::f has been marked final
};
In this example, the virtual void f() final; statement declares a new virtual function, but it also prevents derived classes from overriding it. It also has the effect of preventing derived classes from using that particular function name and parameter combination.
Neither override nor final are language keywords. They are technically identifiers for declarator attributes:
- they gain special meaning as attributes only when used in those specific trailing contexts (after all type specifiers, access specifiers, member declarations (for struct, class and enum types) and declarator specifiers, but before initialization or code implementation of each declarator in a comma-separated list of declarators);
- they do not alter the declared type signature and do not declare or override any new identifier in any scope;
- the recognized and accepted declarator attributes may be extended in future versions of C++ (some compiler-specific extensions already recognize added declarator attributes, to provide code generation options or optimization hints to the compiler, or to generate added data into the compiled code, intended for debuggers, linkers, and deployment of the compiled code, or to provide added system-specific security attributes, or to enhance reflective programming (reflection) abilities at runtime, or to provide added binding information for interoperability with other programming languages and runtime systems; these extensions may take parameters between parentheses after the declarator attribute identifier; for ANSI conformance, these compiler-specific extensions should use the double underscore prefix convention).
- In any other location, they can be valid identifiers for new declarations (and later use if they are accessible).
Null pointer constant and type
[edit]For the purposes of this section and this section alone, every occurrence of "0" is meant as "a constant expression which evaluates to 0, which is of type int". In reality, the constant expression can be of any integral type.
Since the dawn of C in 1972, the constant 0 has had the double role of constant integer and null pointer constant. The ambiguity inherent in the double meaning of 0 was dealt with in C by using the preprocessor macro NULL, which commonly expands to either ((void*)0) or 0. C++ forbids implicit conversion from void* to other pointer types, thus removing the benefit of casting 0 to void*. As a consequence, only 0 is allowed as a null pointer constant. This interacts poorly with function overloading:
void foo(char*);
void foo(int);
If NULL is defined as 0 (which is usually the case in C++), the statement foo(NULL); will call foo(int), which is almost certainly not what the programmer intended, and not what a superficial reading of the code suggests.
C++11 corrects this by introducing a new keyword to serve as a distinguished null pointer constant: nullptr. It is of type nullptr_t, which is implicitly convertible and comparable to any pointer type or pointer-to-member type. It is not implicitly convertible or comparable to integral types, except for bool. While the original proposal specified that an rvalue of type nullptr_t should not be convertible to bool, the core language working group decided that such a conversion would be desirable, for consistency with regular pointer types. The proposed wording changes were unanimously voted into the Working Paper in June 2008.[1] A similar proposal was also brought to the C standard working group and was accepted for inclusion in C23.[17]
For backwards compatibility reasons, 0 remains a valid null pointer constant.
char* pc = nullptr; // OK
int* pi = nullptr; // OK
bool b = nullptr; // OK. b is false.
int i = nullptr; // error
foo(nullptr); // calls foo(nullptr_t), not foo(int);
/*
Note that foo(nullptr_t) will actually call foo(char*) in the example above using an implicit conversion,
only if no other functions are overloading with compatible pointer types in scope.
If multiple overloadings exist, the resolution will fail as it is ambiguous,
unless there is an explicit declaration of foo(nullptr_t).
In standard types headers for C++11, the nullptr_t type should be declared as:
typedef decltype(nullptr) nullptr_t;
but not as:
typedef int nullptr_t; // prior versions of C++ which need NULL to be defined as 0
typedef void* nullptr_t; // ANSI C which defines NULL as ((void*)0)
*/
Strongly typed enumerations
[edit]In C++03, enumerations are not type-safe. They are effectively integers, even when the enumeration types are distinct. This allows the comparison between two enum values of different enumeration types. The only safety that C++03 provides is that an integer or a value of one enum type does not convert implicitly to another enum type. Further, the underlying integral type is implementation-defined; code that depends on the size of the enumeration is thus non-portable. Lastly, enumeration values are scoped to the enclosing scope. Thus, it is not possible for two separate enumerations in the same scope to have matching member names.
C++11 allows a special classification of enumeration that has none of these issues. This is expressed using the enum class (enum struct is also accepted as a synonym) declaration:
enum class CardSuit {
CLUBS = 1,
HEARTS = 2,
DIAMONDS = 4,
SPADES = 8
};
This enumeration is type-safe. Enum class values are not implicitly converted to integers. Thus, they cannot be compared to integers either (the expression CardSuite::SPADES == 8 gives a compile error).
The underlying type of enum classes is always known. The default type is int; this can be overridden to a different integral type as can be seen in this example:
enum class Direction : char {
UP,
DOWN,
LEFT,
RIGHT
};
With old-style enumerations the values are placed in the outer scope. With new-style enumerations they are placed within the scope of the enum class name. So in the above example, UP is undefined, but Direction::UP is defined.
There is also a transitional syntax to allow old-style enumerations to provide explicit scoping, and the definition of the underlying type:
enum Direction : char {
UP,
DOWN,
LEFT,
RIGHT
};
In this case the enumerator names are defined in the enumeration's scope (Direction::UP), but for backwards compatibility they are also placed in the enclosing scope.
Forward-declaring enums is also possible in C++11. Formerly, enum types could not be forward-declared because the size of the enumeration depends on the definition of its members. As long as the size of the enumeration is specified either implicitly or explicitly, it can be forward-declared:
enum Enum1; // Invalid in C++03 and C++11; the underlying type cannot be determined.
enum Enum2 : unsigned int; // Valid in C++11, the underlying type is specified explicitly.
enum class Enum3; // Valid in C++11, the underlying type is int.
enum class Enum4 : unsigned int; // Valid in C++11.
enum Enum2 : unsigned short; // Invalid in C++11, because Enum2 was formerly declared with a different underlying type.
Right angle bracket
[edit]C++03's parser defines “>>” as the right shift operator or stream extraction operator in all cases. However, with nested template declarations, there is a tendency for the programmer to neglect to place a space between the two right angle brackets, thus causing a compiler syntax error.
C++11 improves the specification of the parser so that multiple right angle brackets will be interpreted as closing the template argument list where it is reasonable. This can be overridden by using parentheses around parameter expressions using the “>”, “>=” or “>>” binary operators:
using std::vector;
template <bool Test>
class SomeType;
vector<SomeType<1>2>> x1;
// Interpreted as a std::vector of SomeType<true>,
// followed by "2 >> x1", which is not valid syntax for a declarator. 1 is true.
vector<SomeType<(1>2)>> x1;
// Interpreted as std::vector of SomeType<false>,
// followed by the declarator "x1", which is valid C++11 syntax. (1>2) is false.
Explicit conversion operators
[edit]C++98 added the explicit keyword as a modifier on constructors to prevent single-argument constructors from being used as implicit type conversion operators. However, this does nothing for actual conversion operators. For example, a smart pointer class may have an operator bool() to allow it to act more like a primitive pointer: if it includes this conversion, it can be tested with if (smart_ptr_variable) (which would be true if the pointer was non-null and false otherwise). However, this allows other, unintended conversions as well. Because C++ bool is defined as an arithmetic type, it can be implicitly converted to integral or even floating-point types, which allows for mathematical operations that are not intended by the user.
In C++11, the explicit keyword can now be applied to conversion operators. As with constructors, it prevents using those conversion functions in implicit conversions. However, language contexts that specifically need a Boolean value (the conditions of if-statements and loops, and operands to the logical operators) count as explicit conversions and can thus use a bool conversion operator.
For example, this feature solves cleanly the safe bool issue.
Template aliases
[edit]In C++03, it is possible to define a typedef only as a synonym for another type, including a synonym for a template specialization with all actual template arguments specified. It is not possible to create a typedef template. For example:
template <typename First, typename Second, int Third>
class SomeType;
template <typename Second>
typedef SomeType<OtherType, Second, 5> TypedefName; // Invalid in C++03
This will not compile.
C++11 adds this ability with this syntax:
template <typename First, typename Second, int Third>
class SomeType;
template <typename Second>
using TypedefName = SomeType<OtherType, Second, 5>;
The using syntax can also be used as type aliasing in C++11:
typedef void (*FunctionType)(double); // Old style
using FunctionType = void (*)(double); // New introduced syntax
Unrestricted unions
[edit]In C++03, there are restrictions on what types of objects can be members of a union. For example, unions cannot contain any objects that define a non-trivial constructor or destructor. C++11 lifts some of these restrictions.[2]
If a union member has a non trivial special member function, the compiler will not generate the equivalent member function for the union and it must be manually defined.
This is a simple example of a union permitted in C++11:
#include <new> // Needed for placement 'new'.
struct Point {
int a;
int b;
Point() {}
Point(int x, int y):
x(a), y(b) {}
};
union MyUnion {
int z;
double w;
Point p; // Invalid in C++03; valid in C++11.
// Due to the Point member, a constructor definition is now needed.
MyUnion() {}
MyUnion(const Point& pt):
p(pt) {} // Construct Point object using initializer list.
MyUnion& operator=(const Point& pt) {
// Assign Point object using placement 'new'.
new(&p) Point(pt);
return *this;
}
};
The changes will not break any existing code since they only relax current rules.
Core language functionality improvements
[edit]These features allow the language to do things that were formerly impossible, exceedingly verbose, or needed non-portable libraries.
Variadic templates
[edit]In C++11, templates can take variable numbers of template parameters. This also allows the definition of type-safe variadic functions.
New string literals
[edit]C++03 offers two kinds of string literals. The first kind, contained within double quotes, produces a null-terminated array of type const char. The second kind, defined as L"", produces a null-terminated array of type const wchar_t, where wchar_t is a wide-character of undefined size and semantics. Neither literal type offers support for string literals with UTF-8, UTF-16, or any other kind of Unicode encodings.
C++11 supports three Unicode encodings: UTF-8, UTF-16, and UTF-32. The definition of the type char has been modified to explicitly express that it is at least the size needed to store an eight-bit coding of UTF-8, and large enough to contain any member of the compiler's basic execution character set. It was formerly defined as only the latter in the C++ standard itself, then relying on the C standard to guarantee at least 8 bits. Furthermore, C++11 adds two new character types: char16_t and char32_t. These are designed to store UTF-16 and UTF-32 respectively.
Creating string literals for each of the supported encodings can be done thus:
u8"I'm a UTF-8 string."
u"This is a UTF-16 string."
U"This is a UTF-32 string."
The type of the first string is the usual const char[]. The type of the second string is const char16_t[] (note lower case 'u' prefix). The type of the third string is const char32_t[] (upper case 'U' prefix).
When building Unicode string literals, it is often useful to insert Unicode code points directly into the string. To do this, C++11 allows this syntax:
u8"This is a Unicode Character: \u2018."
u"This is a bigger Unicode Character: \u2018."
U"This is a Unicode Character: \U00002018."
The number after the \u is a hexadecimal number; it does not need the usual 0x prefix. The identifier \u represents a 16-bit Unicode code point; to enter a 32-bit code point, use \U and a 32-bit hexadecimal number. Only valid Unicode code points can be entered. For example, code points on the range U+D800–U+DFFF are forbidden, as they are reserved for surrogate pairs in UTF-16 encodings.
It is also sometimes useful to avoid escaping strings manually, particularly for using literals of XML files, scripting languages, or regular expressions. C++11 provides a raw string literal:
R"(The String Data \ Stuff " )" R"delimiter(The String Data \ Stuff " )delimiter"
In the first case, everything between the "( and the )" is part of the string. The " and \ characters do not need to be escaped. In the second case, the "delimiter( starts the string, and it ends only when )delimiter" is reached. The string delimiter can be any string up to 16 characters in length, including the empty string. This string cannot contain spaces, control characters, (, ), or the \ character. Using this delimiter string, the user can have the sequence )" within raw string literals. For example, R"delimiter("(a-z)")delimiter" is equivalent to "\"(a-z)\"".
Raw string literals can be combined with the wide literal or any of the Unicode literal prefixes:
u8R"XXX(I'm a "raw UTF-8" string.)XXX" uR"*(This is a "raw UTF-16" string.)*" UR"(This is a "raw UTF-32" string.)"
User-defined literals
[edit]C++03 provides a number of literals. The characters 12.5 are a literal that is resolved by the compiler as a type double with the value of 12.5. However, the addition of the suffix f, as in 12.5f, creates a value of type float that contains the value 12.5. The suffix modifiers for literals are fixed by the C++ specification, and C++03 code cannot create new literal modifiers.
By contrast, C++11 enables the user to define new kinds of literal modifiers that will construct objects based on the string of characters that the literal modifies.
Transformation of literals is redefined into two distinct phases: raw and cooked. A raw literal is a sequence of characters of some specific type, while the cooked literal is of a separate type. The C++ literal 1234, as a raw literal, is this sequence of characters '1', '2', '3', '4'. As a cooked literal, it is the integer 1234. The C++ literal 0xA in raw form is '0', 'x', 'A', while in cooked form it is the integer 10.
Literals can be extended in both raw and cooked forms, with the exception of string literals, which can be processed only in cooked form. This exception is due to the fact that strings have prefixes that affect the specific meaning and type of the characters in question.
All user-defined literals are suffixes; defining prefix literals is not possible. All suffixes starting with any character except underscore (_) are reserved by the standard. Thus, all user-defined literals must have suffixes starting with an underscore (_).[18]
User-defined literals processing the raw form of the literal are defined via a literal operator, which is written as operator"". An example follows:
OutputType operator""_mysuffix(const char* literal_string) {
// assumes that OutputType has a constructor that takes a const char*
OutputType ret(literal_string);
return ret;
}
OutputType some_variable = 1234_mysuffix;
// assumes that OutputType has a get_value() method that returns a double
assert(some_variable.get_value() == 1234.0)
The assignment statement OutputType some_variable = 1234_mysuffix; executes the code defined by the user-defined literal function. This function is passed "1234" as a C-style string, so it has a null terminator.
An alternative mechanism for processing integer and floating point raw literals is via a variadic template:
template <char...>
OutputType operator""_tuffix();
OutputType some_variable = 1234_tuffix;
OutputType another_variable = 2.17_tuffix;
This instantiates the literal processing function as operator""_tuffix<'1', '2', '3', '4'>(). In this form, there is no null character terminating the string. The main purpose for doing this is to use C++11's constexpr keyword to ensure that the compiler will transform the literal entirely at compile time, assuming OutputType is a constexpr-constructible and copyable type, and the literal processing function is a constexpr function.
For numeric literals, the type of the cooked literal is either unsigned long long for integral literals or long double for floating point literals. (Note: There is no need for signed integral types because a sign-prefixed literal is parsed as an expression containing the sign as a unary prefix operator and the unsigned number.) There is no alternative template form:
OutputType operator""_suffix(unsigned long long);
OutputType operator""_suffix(long double);
OutputType some_variable = 1234_suffix; // Uses the 'unsigned long long' overload.
OutputType another_variable = 3.1416_suffix; // Uses the 'long double' overload.
In accord with the formerly mentioned new string prefixes, for string literals, these are used:
OutputType operator""_ssuffix(const char* string_values, size_t num_chars);
OutputType operator""_ssuffix(const wchar_t* string_values, size_t num_chars);
OutputType operator""_ssuffix(const char16_t* string_values, size_t num_chars);
OutputType operator""_ssuffix(const char32_t* string_values, size_t num_chars);
OutputType some_variable = "1234"_ssuffix; // Uses the 'const char*' overload.
OutputType some_variable = u8"1234"_ssuffix; // Uses the 'const char*' overload.
OutputType some_variable = L"1234"_ssuffix; // Uses the 'const wchar_t*' overload.
OutputType some_variable = u"1234"_ssuffix; // Uses the 'const char16_t*' overload.
OutputType some_variable = U"1234"_ssuffix; // Uses the 'const char32_t*' overload.
There is no alternative template form. Character literals are defined similarly.
Multithreading memory model
[edit]C++11 standardizes support for multithreaded programming.
There are two parts involved: a memory model which allows multiple threads to co-exist in a program and library support for interaction between threads. (See this article's section on threading facilities.)
The memory model defines when multiple threads may access the same memory location, and specifies when updates by one thread become visible to other threads.
Thread-local storage
[edit]In a multi-threaded environment, it is common for every thread to have some unique variables. This already happens for the local variables of a function, but it does not happen for global and static variables.
A new thread-local storage duration (in addition to the existing static, dynamic and automatic) is indicated by the storage specifier thread_local.
Any object which could have static storage duration (i.e., lifetime spanning the entire execution of the program) may be given thread-local duration instead. The intent is that like any other static-duration variable, a thread-local object can be initialized using a constructor and destroyed using a destructor.
Explicitly defaulted special member functions
[edit]In C++03, the compiler provides, for classes that do not provide them for themselves, a default constructor, a copy constructor, a copy assignment operator (operator=), and a destructor. The programmer can override these defaults by defining custom versions. C++ also defines several global operators (such as operator new) that work on all classes, which the programmer can override.
However, there is very little control over creating these defaults. Making a class inherently non-copyable, for example, may be done by declaring a private copy constructor and copy assignment operator and not defining them. Attempting to use these functions is a violation of the One Definition Rule (ODR). While a diagnostic message is not required,[19] violations may result in a linker error.
In the case of the default constructor, the compiler will not generate a default constructor if a class is defined with any constructors. This is useful in many cases, but it is also useful to be able to have both specialized constructors and the compiler-generated default.
C++11 allows the explicit defaulting and deleting of these special member functions.[20] For example, this class explicitly declares that a default constructor can be used:
class SomeType {
SomeType() = default; // The default constructor is explicitly stated.
SomeType(OtherType value);
};
Explicitly deleted functions
[edit]A function can be explicitly disabled. This is useful for preventing implicit type conversions.
The = delete specifier can be used to prohibit calling a function with particular parameter types.[20] For example:
void noInt(double i);
void noInt(int) = delete;
An attempt to call noInt() with an int parameter will be rejected by the compiler, instead of performing a silent conversion to double. Calling noInt() with a float still works.
It is possible to prohibit calling the function with any type other than double by using a template:
double onlyDouble(double d) {
return d;
}
template<typename T>
double onlyDouble(T) = delete;
calling onlyDouble(1.0) will work, while onlyDouble(1.0f) will generate a compiler error.
Class member functions and constructors can also be deleted. For example, it is possible to prevent copying class objects by deleting the copy constructor and operator =:
class NonCopyable {
NonCopyable();
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
};
Type long long int
[edit]In C++03, the largest integer type is long int. It is guaranteed to have at least as many usable bits as int. This resulted in long int having size of 64 bits on some popular implementations and 32 bits on others. C++11 adds a new integer type long long int to address this issue. It is guaranteed to be at least as large as a long int, and have no fewer than 64 bits. The type was originally introduced by C99 to the standard C, and most C++ compilers supported it as an extension already.[21][22]
Static assertions
[edit]C++03 provides two methods to test assertions: the macro assert and the preprocessor directive #error. However, neither is appropriate for use in templates: the macro tests the assertion at execution-time, while the preprocessor directive tests the assertion during preprocessing, which happens before instantiation of templates. Neither is appropriate for testing properties that are dependent on template parameters.
The new utility introduces a new way to test assertions at compile-time, using the new keyword static_assert.
The declaration assumes this form:
static_assert(constant-expression, error-message);
Here are some examples of how static_assert can be used:
static_assert((GREEKPI > 3.14) && (GREEKPI < 3.15), "GREEKPI is inaccurate!");
template <class T>
struct Check {
static_assert(sizeof(int) <= sizeof(T), "T is not big enough!");
};
using std::is_integral;
template <class Integral>
Integral foo(Integral x, Integral y) {
static_assert(is_integral<Integral>::value, "foo() parameter must be an integral type.");
}
When the constant expression is false the compiler produces an error message. The first example is similar to the preprocessor directive #error, although the preprocessor does only support integral types.[23] In contrast, in the second example the assertion is checked at every instantiation of the template class Check.
Static assertions are useful outside of templates also. For instance, a given implementation of an algorithm might depend on the size of a long long being larger than an int, something the standard does not guarantee. Such an assumption is valid on most systems and compilers, but not all.
Allow sizeof to work on members of classes without an explicit object
[edit]In C++03, the sizeof operator can be used on types and objects. But it cannot be used to do this:
struct SomeType {
OtherType member;
};
sizeof(SomeType::member); // Does not work with C++03. Okay with C++11
This should return the size of OtherType. C++03 disallows this, so it is a compile error. C++11 allows it. It is also allowed for the alignof operator introduced in C++11.
Control and query object alignment
[edit]C++11 allows variable alignment to be queried and controlled with alignof and alignas.
The alignof operator takes the type and returns the power of 2 byte boundary on which the type instances must be allocated (as a std::size_t). When given a reference type alignof returns the referenced type's alignment; for arrays it returns the element type's alignment.
The alignas specifier controls the memory alignment for a variable. The specifier takes a constant or a type; when supplied a type alignas(T) is shorthand for alignas(alignof(T)). For example, to specify that a char array should be properly aligned to hold a float:
alignas(float) unsigned char c[sizeof(float)]
Allow garbage collected implementations
[edit]Prior C++ standards provided for programmer-driven garbage collection via set_new_handler, but gave no definition of object reachability for the purpose of automatic garbage collection. C++11 defines conditions under which pointer values are "safely derived" from other values. An implementation may specify that it operates under strict pointer safety, in which case pointers that are not derived according to these rules can become invalid.
Attributes
[edit]C++11 provides a standardized syntax for compiler/tool extensions to the language. Such extensions were traditionally specified using #pragma directive or vendor-specific keywords (like __attribute__ for GNU and __declspec for Microsoft). With the new syntax, added information can be specified in a form of an attribute enclosed in double square brackets. An attribute can be applied to various elements of source code:
int [[attr1]] i [[attr2, attr3]];
[[attr4(arg1, arg2)]] if (cond) {
[[vendor::attr5]] return i;
}
In the example above, attribute attr1 applies to the type of variable i, attr2 and attr3 apply to the variable itself, attr4 applies to the if statement and vendor::attr5 applies to the return statement. In general (but with some exceptions), an attribute specified for a named entity is placed after the name, and before the entity otherwise, as shown above, several attributes may be listed inside one pair of double square brackets, added arguments may be provided for an attribute, and attributes may be scoped by vendor-specific attribute namespaces.
It is recommended that attributes have no language semantic meaning and do not change the sense of a program when ignored. Attributes can be useful for providing information that, for example, helps the compiler to issue better diagnostics or optimize the generated code.
C++11 provides two standard attributes itself: noreturn to specify that a function does not return, and carries_dependency to help optimizing multi-threaded code by indicating that function arguments or return value carry a dependency.[clarification needed]
C++ standard library changes
[edit]A number of new features were introduced in the C++11 standard library. Many of these could have been implemented under the old standard, but some rely (to a greater or lesser extent) on new C++11 core features.
A large part of the new libraries was defined in the document C++ Standards Committee's Library Technical Report (called TR1), which was published in 2005. Various full and partial implementations of TR1 are currently available using the namespace std::tr1. For C++11 they were moved to namespace std. However, as TR1 features were brought into the C++11 standard library, they were upgraded where appropriate with C++11 language features that were not available in the initial TR1 version. Also, they may have been enhanced with features that were possible under C++03, but were not part of the original TR1 specification.
Upgrades to standard library components
[edit]C++11 offers a number of new language features that the currently existing standard library components can benefit from. For example, most standard library containers can benefit from Rvalue reference based move constructor support, both for quickly moving heavy containers around and for moving the contents of those containers to new memory locations. The standard library components were upgraded with new C++11 language features where appropriate. These include, but are not necessarily limited to:
- Rvalue references and the associated move support
- Support for the UTF-16 encoding unit, and UTF-32 encoding unit Unicode character types
- Variadic templates (coupled with Rvalue references to allow for perfect forwarding)
- Compile-time constant expressions
decltypeexplicitconversion operators- Functions declared defaulted or deleted
Further, much time has passed since the prior C++ standard. Much code using the standard library has been written. This has revealed parts of the standard libraries that could use some improving. Among the many areas of improvement considered were standard library allocators. A new scope-based model of allocators was included in C++11 to supplement the prior model.
Threading facilities
[edit]While the C++03 language provides a memory model that supports threading, the primary support for actually using threading comes with the C++11 standard library.
A thread class (std::thread) is provided, which takes a function object (and an optional series of arguments to pass to it) to run in the new thread. It is possible to cause a thread to halt until another executing thread completes, providing thread joining support via the std::thread::join() member function. Access is provided, where feasible, to the underlying native thread object(s) for platform-specific operations by the std::thread::native_handle() member function.
For synchronization between threads, appropriate mutexes (std::mutex, std::recursive_mutex, etc.) and condition variables (std::condition_variable and std::condition_variable_any) are added to the library. These are accessible via Resource Acquisition Is Initialization (RAII) locks (std::lock_guard and std::unique_lock) and locking algorithms for easy use.
For high-performance, low-level work, communicating between threads is sometimes needed without the overhead of mutexes. This is done using atomic operations on memory locations. These can optionally specify the minimum memory visibility constraints needed for an operation. Explicit memory barriers may also be used for this purpose.
The C++11 thread library also includes futures and promises for passing asynchronous results between threads, and std::packaged_task for wrapping up a function call that can generate such an asynchronous result. The futures proposal was criticized because it lacks a way to combine futures and check for the completion of one promise inside a set of promises.[24]
Further high-level threading facilities such as thread pools have been remanded to a future C++ technical report. They are not part of C++11, but their eventual implementation is expected to be built entirely on top of the thread library features.
The new std::async facility provides a convenient method of running tasks and tying them to a std::future. The user can choose whether the task is to be run asynchronously on a separate thread or synchronously on a thread that waits for the value. By default, the implementation can choose, which provides an easy way to take advantage of hardware concurrency without oversubscription, and provides some of the advantages of a thread pool for simple usages.
Tuple types
[edit]Tuples are collections composed of heterogeneous objects of pre-arranged dimensions. A tuple can be considered a generalization of a struct's member variables.
The C++11 version of the TR1 tuple type benefited from C++11 features like variadic templates. To implement reasonably, the TR1 version required an implementation-defined maximum number of contained types, and substantial macro trickery. By contrast, the implementation of the C++11 version requires no explicit implementation-defined maximum number of types. Though compilers will have an internal maximum recursion depth for template instantiation (which is normal), the C++11 version of tuples will not expose this value to the user.
Using variadic templates, the declaration of the tuple class looks as follows:
namespace std {
template <class... Types>
class tuple;
}
An example of definition and use of the tuple type:
typedef std::tuple<int, double, long&, const char*> TestTuple;
long lengthy = 12;
TestTuple proof(18, 6.5, lengthy, "Ciao!");
lengthy = std::get<0>(proof); // Assign to 'lengthy' the value 18.
std::get<3>(proof) = " Beautiful!"; // Modify the tuple’s fourth element.
It's possible to create the tuple proof without defining its contents, but only if the tuple elements' types possess default constructors. Moreover, it's possible to assign a tuple to another tuple: if the two tuples’ types are the same, each element type must possess a copy constructor; otherwise, each element type of the right-side tuple must be convertible to that of the corresponding element type of the left-side tuple or that the corresponding element type of the left-side tuple has a suitable constructor.
typedef std::tuple<int, double, string> Tuple1 t1;
typedef std::tuple<char, short, const char*> Tuple2 t2 ('X', 2, "Hola!");
t1 = t2; // Ok, first two elements can be converted,
// the third one can be constructed from a 'const char *'.
Just like std::make_pair for std::pair, there exists std::make_tuple to automatically create std::tuples using type deduction and auto helps to declare such a tuple. std::tie creates tuples of lvalue references to help unpack tuples. std::ignore also helps here. See the example:
using std::string;
auto record = std::make_tuple("Hari Ram", "New Delhi", 3.5, 'A');
string name;
float gpa;
char grade;
std::tie(name, std::ignore, gpa, grade) = record ; // std::ignore helps drop the place name
std::cout << name << ' ' << gpa << ' ' << grade << std::endl ;
Relational operators are available (among tuples with the same number of elements), and two expressions are available to check a tuple's characteristics (only during compilation):
std::tuple_size<T>::valuereturns the number of elements in the tupleT,std::tuple_element<I, T>::typereturns the type of the object numberIof the tupleT.
Hash tables
[edit]Including hash tables (unordered associative containers) in the C++ standard library is one of the most recurring requests. It was not adopted in C++03 due to time constraints only. Although hash tables are less efficient than a balanced tree in the worst case (in the presence of many collisions), they perform better in many real applications.
Collisions are managed only via linear chaining because the committee didn't consider it to be opportune to standardize solutions of open addressing that introduce quite a lot of intrinsic problems (above all when erasure of elements is admitted). To avoid name clashes with non-standard libraries that developed their own hash table implementations, the prefix “unordered” was used instead of “hash”.
The new library has four types of hash tables, differentiated by whether or not they accept elements with the same key (unique keys or equivalent keys), and whether they map each key to an associated value. They correspond to the four existing binary search tree based associative containers, with an unordered_ prefix.
| Type of hash table | Associated values | Equivalent keys |
|---|---|---|
std::unordered_set |
No | No |
std::unordered_multiset |
No | Yes |
std::unordered_map |
Yes | No |
std::unordered_multimap |
Yes | Yes |
The new classes fulfill all the requirements of a container class, and have all the methods needed to access elements: insert, erase, begin, end.
This new feature didn't need any C++ language core extensions (though implementations will take advantage of various C++11 language features), only a small extension of the header <functional> and the introduction of headers <unordered_set> and <unordered_map>. No other changes to any existing standard classes were needed, and it doesn't depend on any other extensions of the standard library.
std::array and std::forward_list
[edit]In addition to the hash tables two more containers was added to the standard library. The std::array is a fixed size container that is more efficient than std::vector but safer and easier to use than a c-style array. The std::forward_list is a single linked list that provides more space efficient storage than the double linked std::list when bidirectional iteration is not needed.
Regular expressions
[edit]The new library, defined in the new header <regex>, is made of a couple of new classes:
- regular expressions are represented by instance of the template class
std::regex; - occurrences are represented by instance of the template class
std::match_results, - std::regex_iterator is used to iterate over all matches of a regex
The function std::regex_search is used for searching, while for ‘search and replace’ the function std::regex_replace is used which returns a new string.[25]
Here is an example of the use of std::regex_iterator:
#include <regex>
using std::cregex_iterator;
using std::regex;
using std::string;
const char* pattern = R"([^ ,.\t\n]+)"; // find words separated by space, comma, period tab newline
regex re(pattern); // throws exception on invalid pattern
const char* target = "Unseen University - Ankh-Morpork";
// Use a regex_iterator to identify all words of 'target' separated by characters of 'pattern'.
cregex_iterator iter(target, target + strlen(target), re);
// make an end of sequence iterator
cregex_iterator end();
for (; iter != end; ++iter)
{
string match_str = iter->str();
std::cout << match_str << std::endl;
}
The library <regex> requires neither alteration of any existing header (though it will use them where appropriate) nor an extension of the core language. In POSIX C, regular expressions are also available via the C POSIX library#regex.h.
General-purpose smart pointers
[edit]C++11 provides std::unique_ptr, and improvements to std::shared_ptr and std::weak_ptr from TR1. std::auto_ptr is deprecated.
Extensible random number facility
[edit]The C standard library provides the ability to generate pseudorandom numbers via the function rand. However, the algorithm is delegated entirely to the library vendor. C++ inherited this functionality with no changes, but C++11 provides a new method for generating pseudorandom numbers.
C++11's random number functionality is split into two parts: a generator engine that contains the random number generator's state and produces the pseudorandom numbers; and a distribution, which determines the range and mathematical distribution of the outcome. These two are combined to form a random number generator object.
Unlike the C standard rand, the C++11 mechanism will come with three base generator engine algorithms:
C++11 also provides a number of standard distributions:
uniform_int_distribution,uniform_real_distribution,bernoulli_distribution,binomial_distribution,geometric_distribution,negative_binomial_distribution,poisson_distribution,exponential_distribution,gamma_distribution,weibull_distribution,extreme_value_distribution,normal_distribution,lognormal_distribution,chi_squared_distribution,cauchy_distribution,fisher_f_distribution,student_t_distribution,discrete_distribution,piecewise_constant_distributionandpiecewise_linear_distribution.
The generator and distributions are combined as in this example:
#include <random>
#include <functional>
using std::mt19937;
using std::uniform_int_distribution;
uniform_int_distribution<int> distribution(0, 99);
mt19937 engine; // Mersenne twister MT19937
auto generator = std::bind(distribution, engine);
int random = generator(); // Generate a uniform integral variate between 0 and 99.
int random2 = distribution(engine); // Generate another sample directly using the distribution and the engine objects.
Wrapper reference
[edit]A wrapper reference is obtained from an instance of the class template reference_wrapper. Wrapper references are similar to normal references (‘&’) of the C++ language. To obtain a wrapper reference from any object the function template ref is used (for a constant reference cref is used).
Wrapper references are useful above all for function templates, where references to parameters rather than copies are needed:
// This function will take a reference to the parameter 'r' and increment it.
void func(int& r) {
r++;
}
// Template function.
template <class F, class P>
void g(F f, P t) {
f(t);
}
int main() {
int i = 0;
g(func, i);
// 'g<void(int& r), int>' is instantiated
// then 'i' will not be modified.
std::cout << i << std::endl; // Output -> 0
g(func, std::ref(i));
// 'g<void(int& r), reference_wrapper<int>>' is instantiated
// then 'i' will be modified.
std::cout << i << std::endl; // Output -> 1
}
This new utility was added to the existing <functional> header and didn't need further extensions of the C++ language.
Polymorphic wrappers for function objects
[edit]Polymorphic wrappers for function objects are similar to function pointers in semantics and syntax, but are less tightly bound and can indiscriminately refer to anything which can be called (function pointers, member function pointers, or functors) whose arguments are compatible with those of the wrapper.
An example can clarify its characteristics:
using std::function;
using std::plus;
// Wrapper creation using template class 'function'.
function<int(int, int)> func;
plus<int> add;
// 'plus' is declared as 'template <class T> T plus(T, T) ;'
// then 'add' is type 'int add( int x, int y )'.
func = add; // OK - Parameters and return types are the same.
int a = func(1, 2);
// NOTE: if the wrapper 'func' does not refer to any function,
// the exception 'std::bad_function_call' is thrown.
function<bool(short, short)> func2;
if (!func2) {
// True because 'func2' has not yet been assigned a function.
bool adjacent(long x, long y);
func2 = &adjacent; // OK - Parameters and return types are convertible.
struct Test {
bool operator()(short x, short y);
};
Test car;
// 'std::ref' is a template function that returns the wrapper
// of member function 'operator()' of struct 'car'.
func = std::ref(car);
}
func = func2; // OK - Parameters and return types are convertible.
The template class function was defined inside the header <functional>, without needing any change to the C++ language.
Type traits for metaprogramming
[edit]Metaprogramming consists of creating a program that creates or modifies another program (or itself). This can happen during compilation or during execution. The C++ Standards Committee has decided to introduce a library for metaprogramming during compiling via templates.
Here is an example of a meta-program using the C++03 standard: a recursion of template instances for calculating integer exponents:
template <int B, int N>
struct Pow {
// recursive call and recombination.
enum {
value = B * Pow<B, N - 1>::value
};
};
template <int B>
struct Pow<B, 0> {
// ''N == 0'' condition of termination.
enum {
value = 1
};
};
int quartic_of_three = Pow<3, 4>::value;
Many algorithms can operate on different types of data; C++'s templates support generic programming and make code more compact and useful. Nevertheless, it is common for algorithms to need information on the data types being used. This information can be extracted during instantiation of a template class using type traits.
Type traits can identify the category of an object and all the characteristics of a class (or of a struct). They are defined in the new header <type_traits>.
In the next example there is the template function ‘elaborate’ which, depending on the given data types, will instantiate one of the two proposed algorithms (Algorithm::do_it).
using std::is_floating_point;
using std::is_integral;
// First way of operating.
template <bool B>
struct Algorithm {
template <class T1, class T2>
static int do_it(T1&, T2&) {
// ...
}
};
// Second way of operating.
template <>
struct Algorithm<true> {
template <class T1, class T2>
static int do_it(T1, T2) {
// ...
}
};
// Instantiating 'elaborate' will automatically instantiate the correct way to operate.
template <class T1, class T2>
int elaborate(T1 A, T2 B) {
// Use the second way only if 'T1' is an integer and if 'T2' is
// in floating point, otherwise use the first way.
return Algorithm<is_integral<T1>::value && is_floating_point<T2>::value>::do_it( A, B ) ;
}
Via type traits, defined in header <type_traits>, it's also possible to create type transformation operations (static_cast and const_cast are insufficient inside a template).
This type of programming produces elegant and concise code; however, the weak point of these techniques is the debugging: it's uncomfortable during compilation and very difficult during program execution.
Uniform method for computing the return type of function objects
[edit]Determining the return type of a template function object at compile-time is not intuitive, particularly if the return value depends on the parameters of the function. As an example:
struct Clear {
// The parameter type is equal to the return type.
int operator()(int) const;
double operator()(double) const;
};
template <class Obj>
class Calculus {
private:
Obj member;
public:
template <class Arg>
Arg operator()(Arg& a) const {
return member(a);
}
};
Instantiating the class template Calculus<Clear>, the function object of calculus will have always the same return type as the function object of Clear. However, given class Confused below:
struct Confused {
// The parameter type is not equal to the return type.
double operator()(int) const;
int operator()(double) const;
};
Attempting to instantiate Calculus<Confused> will cause the return type of Calculus to not be the same as that of class Confused. The compiler may generate warnings about the conversion from int to double and vice versa.
TR1 introduces, and C++11 adopts, the template class std::result_of that allows one to determine and use the return type of a function object for every declaration. The object CalculusVer2 uses the std::result_of object to derive the return type of the function object:
using std::result_of;
template <class Obj>
class CalculusVer2 {
private:
Obj member;
public:
template <class Arg>
typename result_of<Obj(Arg)>::type operator()(Arg& a) const {
return member(a);
}
};
In this way in instances of function object of CalculusVer2<Confused> there are no conversions, warnings, or errors.
The only change from the TR1 version of std::result_of is that the TR1 version allowed an implementation to fail to be able to determine the result type of a function call. Due to changes to C++ for supporting decltype, the C++11 version of std::result_of no longer needs these special cases; implementations are required to compute a type in all cases.
Improved C compatibility
[edit]For compatibility with C, from C99, these were added:[26]
- Preprocessor:[27]
- variadic macros,
- concatenation of adjacent narrow/wide string literals,
_Pragma()– equivalent of#pragma.
long long– integer type that is at least 64 bits long.__func__– macro evaluating to the name of the function it is in.- Headers:
cstdbool(stdbool.h),cstdint(stdint.h),cinttypes(inttypes.h).
Features originally planned but removed or not included
[edit]Heading for a separate TR:
- Modules
- Decimal types
- Math special functions
Postponed:
- Concepts
- More complete or required garbage collection support
- Reflection
- Macro scopes
Features removed or deprecated
[edit]The term sequence point was removed, being replaced by specifying that either one operation is sequenced before another, or that two operations are unsequenced.[28]
The former use of the keyword export was removed.[29] The keyword itself remains, being reserved for potential future use.
Dynamic exception specifications are deprecated.[29] Compile-time specification of non-exception-throwing functions is available with the noexcept keyword, which is useful for optimization.
std::auto_ptr is deprecated, having been superseded by std::unique_ptr.
Function object base classes (std::unary_function, std::binary_function), adapters to pointers to functions and adapters to pointers to members, and binder classes are all deprecated.
Annex D.2 states: "The use of the register keyword as a storage-class-specifier (§7.1.1) is deprecated."
See also
[edit]References
[edit]- ^ "We have an international standard: C++0x is unanimously approved". 12 August 2011. Archived from the original on 11 December 2018. Retrieved 12 August 2011.
- ^ a b Stroustrup, Bjarne. "C++11 FAQ". stroustrup.com. Archived from the original on 2018-10-06. Retrieved 2014-10-15.
- ^ a b "C++11 Overview: What specific design goals guided the committee?". Standard C++. Archived from the original on 2019-01-31. Retrieved 2015-09-04.
- ^ "Bjarne Stroustrup: A C++0x overview" (PDF). Archived (PDF) from the original on 17 June 2016. Retrieved 30 June 2011.
- ^ "ISO/IEC 14882:2011". ISO. 2 September 2011. Archived from the original on 29 January 2013. Retrieved 3 September 2011.
- ^ "Working Draft, Standard for Programming Language C++" (PDF). Archived (PDF) from the original on 2019-01-21. Retrieved 2012-04-26.
- ^ "The Standard". Standard C++ Foundation. Archived from the original on 2012-11-05. Retrieved 2012-11-02.
Except only for the final standards/reports, all C++ committee documents are freely publicly available, including all working drafts, many of which closely approximate the published standard. The January 2012 working draft contains the C++11 standard plus minor editorial changes.
- ^ "Clang - C++ Programming Language Status". 2023-11-29. Archived from the original on 2023-11-29. Retrieved 2023-12-01.
- ^ "GCC 4.8.1 released, C++11 feature complete: Standard C++". isocpp.org. Retrieved 2023-12-01.
- ^ Sutter, Alexandrescu "C++ coding standards" #15
- ^ Gabriel Dos Reis; Bjarne Stroustrup (22 March 2010). "General Constant Expressions for System Programming Languages, Proceedings SAC '10" (PDF). Archived (PDF) from the original on 13 June 2018. Retrieved 18 August 2012.
- ^ Jaakko Järvi; Bjarne Stroustrup; Douglas Gregor; Jeremy Siek (April 28, 2003). "Decltype and auto, Programming Language C++, Document no: N1478=03-0061" (PDF). Archived (PDF) from the original on May 28, 2015. Retrieved June 6, 2015.
- ^ Roger Orr (June 2013). ""Auto – A Necessary Evil?" Overload Journal #115". Archived from the original on 2015-06-06. Retrieved 2015-06-06.
- ^ "Document no: N1968=06-0038- Lambda expressions and closures for C++" (PDF). Open Standards. Archived (PDF) from the original on 2011-07-28. Retrieved 2009-04-20.
- ^ "Decltype (revision 5)" (PDF). Archived (PDF) from the original on 2022-02-14. Retrieved 2022-02-16.
- ^ "auto specifier (since C++11) - cppreference.com". en.cppreference.com. Archived from the original on 2016-10-20. Retrieved 2016-10-18.
- ^ Gustedt, Jens (2019-07-09). "Introduce the nullptr constant - v1" (PDF). ISO JTC1/SC22/WG14 Document Register. International Organization for Standardization. Archived (PDF) from the original on 2020-07-27. Retrieved 2020-04-19 – via open-std.org.
- ^ This caused a conflict with the proposed use (common in other languages) of the underscore for digit grouping in numeric literals such as integer literals, so C++14 instead uses the apostrophe (as an upper comma) for grouping.Daveed Vandevoorde (2012-09-21). "N3448: Painless Digit Separation" (PDF). Archived (PDF) from the original on 2015-08-11. Retrieved 2015-08-13., Lawrence Crowl (2012-12-19). "N3499: Digit Separators". Archived from the original on 2015-08-11. Retrieved 2015-08-13.
- ^ ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages – C++ §3.2 One definition rule [basic.def.odr] para. 3
- ^ a b "Defaulted and Deleted Functions – ISO/IEC JTC1 SC22 WG21 N2210 = 07-0070 – 2007-03-11". Archived from the original on 2012-08-19. Retrieved 2012-12-20.
- ^ "Using the GNU Compiler Collection (GCC): Long Long". gcc.gnu.org. Archived from the original on 2016-08-21. Retrieved 2016-07-25.
- ^ "Data Type Ranges (C++)". Archived from the original on 2009-02-21. Retrieved 2009-04-23.
- ^ Samuel P. Harbison III, Guy L. Steele Jr.: "C – A Reference Manual", 5th edition, p.251
- ^ Milewski, Bartosz (3 March 2009). "Broken promises–C++0x futures". Archived from the original on 16 September 2011. Retrieved 24 January 2010.
- ^ "C++ Regular expressions library". cppreference.com. Retrieved 10 December 2022.
- ^ "Clang - C++98, C++11, and C++14 Status". Clang.llvm.org. 2013-05-12. Archived from the original on 2019-05-28. Retrieved 2013-06-10.
- ^ "Working draft changes for C99 preprocessor synchronization". www.open-std.org. Archived from the original on 2020-07-31. Retrieved 2014-05-26.
- ^ Caves, Jonathan (4 June 2007). "Update on the C++-0x Language Standard". Archived from the original on 9 September 2011. Retrieved 25 May 2010.
- ^ a b Sutter, Herb (3 March 2010). "Trip Report: March 2010 ISO C++ Standards Meeting". Archived from the original on 11 July 2018. Retrieved 24 March 2010.
External links
[edit]This section's use of external links may not follow Wikipedia's policies or guidelines. (October 2018) |
- The C++ Standards Committee
- C++0X: The New Face of Standard C++
- Herb Sutter's blog coverage of C++11
- Anthony Williams' blog coverage of C++11
- A talk on C++0x given by Bjarne Stroustrup at the University of Waterloo Archived 2009-01-23 at the Wayback Machine
- The State of the Language: An Interview with Bjarne Stroustrup (15 August 2008) Archived 31 January 2009 at the Wayback Machine
- Wiki page to help keep track of C++ 0x core language features and their availability in compilers
- Online C++11 standard library reference
- Online C++11 compiler
- Bjarne Stroustrup's C++11 FAQ
- More information on C++11 features:range-based for loop, why auto_ptr is deprecated, etc.
C++11
View on GrokipediaHistory and Standardization
Development Timeline
The development of C++11, initially referred to as C++0x, was initiated by the ISO/IEC JTC1/SC22/WG21 committee in 2006, building on the C++98 and C++03 standards to address evolving needs in systems programming, performance, and usability.[5] This effort followed the publication of the C++03 Technical Corrigendum in 2003, with early preparatory work including the Draft Technical Report on C++ Library Extensions (TR1) circulated in 2005 and formally published as ISO/IEC TR 19768:2007 in November 2007, which introduced library extensions like smart pointers, regular expressions, and mathematical functions that later influenced C++11.[6] Similarly, proposals for a second technical report (TR2), solicited starting in 2005, contributed concepts such as advanced filesystem and networking support, many of which were ultimately integrated directly into the C++11 standard rather than a separate report.[7] Bjarne Stroustrup, the creator of C++ and convener of WG21, played a central role in guiding the standardization process, advocating for balanced evolution while the Evolution Working Group (EWG) evaluated and refined core language proposals through regular meetings.[5] The timeline encountered delays primarily due to the technical complexity of integrating modern features, including prolonged debates within the Concurrency Working Group from 2007 to 2010 on defining a robust memory model to ensure predictable behavior in multithreaded programs without overly restricting compiler optimizations.[8] These discussions, involving formal semantic analyses, extended the expected completion from 2009 to 2011, prioritizing thoroughness over haste.[9] Key milestones included the release of the first working draft in September 2008 for committee review and the approval of the Final Committee Draft (FCD) on March 25, 2011, after iterative refinements.[5] The draft then underwent the Final Draft International Standard (FDIS) ballot, achieving unanimous approval (21-0) when the ISO ballot closed on August 12, 2011.[10] The standard was officially published in September 2011 as ISO/IEC 14882:2011, marking the third edition of the C++ International Standard.[1]Design Goals and Principles
The primary design goals of C++11 centered on enhancing the language's capabilities for systems programming while ensuring direct and universal access to hardware resources, thereby supporting efficient low-level operations without intermediaries.[11] This included providing stronger support for constructing large-scale software systems through improved abstraction mechanisms that facilitate modularity and scalability.[5] Additionally, the standard aimed to address gaps relative to contemporary languages by incorporating features for more expressive and concise code, all while maintaining strict backward compatibility with C++98 and C++03 to preserve existing codebases and minimize migration costs.[12] Guiding principles emphasized zero-overhead abstractions, ensuring that high-level language constructs impose no runtime or space penalties compared to equivalent hand-optimized code, thus preserving C++'s performance advantages.[5] The design reinforced the resource acquisition is initialization (RAII) idiom, promoting deterministic resource management through object lifetimes to prevent leaks and errors in complex applications.[11] Exception safety was upheld as a core tenet, with new features designed to integrate seamlessly into exception-handling frameworks without introducing undefined behaviors or weakening guarantees.[5] C++11 placed strong emphasis on achieving performance parity with C, particularly in single-threaded scenarios, while introducing multithreading support that avoids compromising efficiency in non-concurrent code paths.[11] This was driven by the need to adapt to modern hardware architectures, such as multicore processors, enabling scalable parallelism through a standardized memory model and atomic operations without overhead for sequential execution.[12] Usability improvements focused on simplifying common tasks, like initialization and iteration, to reduce boilerplate while retaining fine-grained control for performance-critical domains.[5] Influences from languages like Java and C# informed additions in areas such as generics via templates and lambda expressions for functional-style programming, yet these were adapted to align with C++'s systems programming roots, prioritizing compile-time resolution over runtime dynamism.[11] The overarching target was to evolve C++ into a "better C++" that is simpler to teach and use for a broader audience, including novices, without diluting its power for expert systems developers or introducing unnecessary complexity.[5]Core Language Enhancements
Runtime Performance Improvements
C++11 introduced rvalue references, denoted by&&, to distinguish between lvalue and rvalue expressions, enabling more efficient resource management by allowing temporary objects to be moved rather than copied.[13] This feature supports move semantics, where resources such as dynamically allocated memory can be transferred from one object to another without duplication, reducing runtime overhead in scenarios involving temporaries.[14] For instance, in string concatenation like std::string s = std::string("hello") + std::string(" world");, rvalue references facilitate moving the contents of temporary strings, minimizing allocations.[13]
Move constructors and move assignment operators leverage rvalue references to implement this transfer, using syntax such as Class(Class&& other) for the constructor and Class& operator=(Class&& other) for assignment.[13] The std::move utility casts lvalues to rvalues, triggering these operations when appropriate, as in v.emplace_back(std::move(x)); to insert into a container without copying.[14] Perfect forwarding, achieved via rvalue references in template parameters and std::forward, preserves argument categories during function calls, avoiding unnecessary copies in generic code.[13]
The constexpr specifier allows functions to perform computations at compile time when invoked with constant expressions, potentially embedding results directly into the code for faster runtime execution.[15] In C++11, such functions are restricted to literal return types, literal parameters, and a single return statement without loops or non-literal variable definitions.[16] An example is a recursive factorial function:
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
constexpr int f5 = factorial(5);, it evaluates to 120 at compile time, eliminating runtime calculation.[15]
C++11 revised the definition of plain old data (POD) types by splitting it into trivial and standard-layout categories, enhancing optimization opportunities and C interoperability.[17] Trivial types have compiler-generated special member functions (default constructor, copy operations, destructor) and lack virtual functions, virtual bases, or nontrivial members/bases, allowing bitwise copies via memcpy.[17] Standard-layout types are classes or unions that satisfy layout rules for predictable memory layout, including no virtual functions or virtual bases, all non-static data members having the same access control, no non-static data members of reference type, and either no base classes with non-static data members or all base classes being standard-layout. Standard-layout types may have nontrivial constructors.[18][17] A POD type is both trivial and standard-layout, with all non-static members also PODs, facilitating low-level optimizations like efficient serialization.[17]
These features collectively improve runtime performance by reducing copy operations and enabling compile-time optimizations. For example, move semantics in std::vector allow O(1) swaps and insertions of large objects by transferring ownership, avoiding deep copies that could otherwise dominate execution time.[13] Benchmarks demonstrate up to 16% faster runtime in scenarios with frequent temporary constructions, such as container manipulations without compiler optimizations.[19]
Build-Time Performance Improvements
C++11 introduced theextern template declaration to address compilation inefficiencies arising from implicit template instantiations in multiple translation units. This feature allows developers to explicitly declare that a particular template specialization should not be implicitly instantiated in the current translation unit, relying instead on an explicit instantiation defined elsewhere. For instance, the declaration extern template class std::vector<int>; suppresses the generation of code for std::vector<int> in the file where it appears, preventing redundant work when the same specialization is used across many source files.[20][21]
In large-scale projects with heavy template usage, such as those involving standard library containers or custom generic code, implicit instantiations can lead to substantial compile-time overhead due to repeated code generation and analysis. By using extern template, compilation times are reduced because the compiler skips instantiation in most units, instantiating the template only once in a designated source file via explicit instantiation (e.g., template class std::vector<int>;). This approach also minimizes binary size by avoiding duplicate object code in intermediate files, though the final linked executable remains unaffected as the linker resolves the single definition. Linkage rules ensure the instantiated definition is accessible across units, making the feature particularly valuable for optimizing builds in template-intensive codebases.[21][22]
However, extern template requires careful management: the explicit instantiation must occur in exactly one translation unit, and failure to provide it results in linker errors at build time. It applies only to full specializations and does not influence runtime performance, focusing solely on compile-time and object file size reductions. Template aliases, also new in C++11, can complement this by simplifying verbose extern template declarations for complex types.[20][22]
Usability Enhancements
C++11 introduced a suite of syntactic and structural improvements designed to streamline common programming tasks, reduce boilerplate code, and enhance type safety without altering the core semantics of the language. These enhancements primarily target everyday coding practices, making C++ more approachable while minimizing subtle errors that plagued earlier versions. Key among them are features like uniform initialization and type inference, which address longstanding pain points in object creation and variable declaration. Initializer lists enable the use of brace-enclosed sequences, such as{1, 2, 3}, to initialize aggregates and extend this capability to containers through the std::initializer_list<T> template. This allows concise construction of standard library containers, for example, std::vector<int> v{1, 2, 3};, promoting uniformity in initialization syntax across built-in arrays and user-defined types.[23]
Building on initializer lists, uniform initialization employs the same brace syntax {} for all object types, including scalars, aggregates, and class objects with constructors. This approach prevents narrowing conversions—for instance, int x{2.5}; fails to compile due to the potential loss of precision—and resolves ambiguities like the "most vexing parse," where a function declaration is inadvertently created instead of an object. By standardizing initialization, it fosters consistent code patterns and reduces unexpected behaviors in constructor overload resolution.[23]
The auto keyword facilitates automatic type deduction for variables, simplifying declarations involving complex types. For example, auto i = std::find(v.begin(), v.end(), 42); infers i as std::vector<int>::iterator without requiring the full type to be spelled out, which is particularly useful for iterator and template-heavy code. This feature extends to function return types and lambda parameters in later contexts, easing maintenance in generic programming.[24]
Range-based for loops provide a declarative syntax for iterating over containers and ranges, such as for (auto& elem : container) { /* process elem */ }, which desugars to traditional iterator usage via begin() and end() calls. This eliminates the need for explicit iterator management, reducing verbosity and errors in loops over arrays, vectors, or other iterable types, while supporting const-correctness through reference qualifiers.
Lambda expressions introduce inline anonymous functions with the syntax [capture](parameters) mutable noexcept -> return_type { body }, allowing captures by value or reference to enclose local variables. The mutable keyword permits modification of captured values, and various capture modes (e.g., [&] for all by reference) enable flexible closures for algorithms like std::sort or event handlers. This construct integrates seamlessly with the standard library, enhancing functional-style programming without requiring separate function objects.
To improve virtual function management, C++11 adds override and final specifiers for method declarations. The override keyword explicitly indicates intent to override a base class virtual function, triggering a compile-time error if the signature mismatches, thus catching refactoring mistakes early. Similarly, final prevents further overriding in derived classes, useful for sealing interfaces or optimizing dispatch in class hierarchies. For instance, virtual void foo() override; ensures correctness in polymorphic code.[25]
The nullptr constant serves as a type-safe null pointer literal, distinct from integer zero or macro NULL, preventing overload resolution ambiguities in functions accepting both pointers and integers. Usage like if (ptr == nullptr) ensures clearer intent and avoids errors in pointer comparisons, with nullptr being convertible only to pointer types.
Strongly typed enums, declared as enum class Name : underlying_type { enumerator = value };, introduce scoped enumerators that do not implicitly convert to integers, mitigating namespace pollution and unintended conversions. For example, enum class Color : int { Red = 1 }; requires explicit casting for numeric operations, enhancing safety in switch statements and arithmetic contexts.
A parsing fix resolves the ambiguity of consecutive right angle brackets in nested templates, allowing std::vector<std::vector<int>> to compile without spaces, as in pre-C++11 where >> was treated as a right-shift operator. This streamlines template instantiation syntax for multi-dimensional containers.
Explicit conversion operators, marked with the explicit keyword like explicit operator bool() const;, disallow implicit conversions unless an explicit cast is applied, reducing surprises in contexts like conditional expressions. This control is vital for types like smart pointers, where implicit bool conversion might lead to unintended evaluations.
Template aliases, using template <typename T> using Alias = SomeTemplate<T>;, create readable synonyms for complex template types, such as using IntVec = std::vector<int>;. This improves code legibility without introducing new types, aiding in the definition of generic aliases for iterators or allocators.
Unrestricted unions permit non-trivial members (those with constructors or destructors) within unions, tracked via an active member designator. Constructors can initialize specific members, enabling unions to hold objects with resources, provided only the active member is accessed—violations are undefined behavior. This expands union utility for variant-like types while maintaining layout guarantees.
Defaulted and deleted special member functions allow explicit control over compiler-generated behaviors: = default requests the compiler to provide an implementation (e.g., for copy constructors), while = delete disables it entirely, such as MyClass(const MyClass&) = delete; to prevent copying. This facilitates rule-of-three/five adherence and custom resource management in classes.
Finally, static_assert supports compile-time boolean assertions, as in static_assert(sizeof(int) == 4, "Platform mismatch");, halting compilation with a custom message if false. This enables early detection of assumptions about types, constants, or configurations, integrating seamlessly with templates for portable code.
Functionality Additions
C++11 introduced variadic templates, enabling the definition of class and function templates that accept a variable number of template parameters through parameter packs. A parameter pack, denoted by ellipsis (...), captures zero or more arguments, such as in template<typename... Args> void print(Args... args);, allowing functions to handle arbitrary argument counts. This feature supports expansion of packs using recursion or, later, fold expressions, and provides utilities like sizeof...(Args) to query pack size, facilitating more flexible generic programming without manual overload sets.[26]
Raw string literals were added to simplify the representation of strings containing special characters, such as quotes or backslashes, without requiring escape sequences. Formed as R"(content)", these literals preserve the content as-is, making them ideal for multiline text, regular expressions, or HTML snippets; custom delimiters can be used, like R"delimiter(content)delimiter", to avoid conflicts with closing parentheses. User-defined literals extend this further, allowing custom suffixes via operator"", for example, 5.2_km to represent units, enhancing type safety and expressiveness in domain-specific code.[27]
The long long int type, already present in earlier standards, received formal guarantees in C++11 through fixed-width integer types in the <cstdint> header, ensuring int64_t as a signed 64-bit integer and uint64_t as unsigned, with literals suffixed by LL or ULL (e.g., 1LL). This standardization aligns C++ with C99 practices, providing portable 64-bit arithmetic essential for large datasets or cryptography, while avoiding platform-dependent sizes of long.
C++11 extended the sizeof operator to non-static data members and base classes without requiring an object instance, as in sizeof(MyClass::member). This compile-time evaluation aids in template metaprogramming and resource planning, such as calculating offsets or sizes in generic containers, without instantiating potentially expensive objects.[28]
The alignas and alignof keywords provide control and inquiry over memory alignment, critical for performance in SIMD operations or hardware constraints. alignof(Type) returns the alignment requirement in bytes for a type, while alignas(n) Type var; specifies that var must align to a multiple of n (a power of two), as in alignas(16) char buf[100]; for vectorized access; over-alignment beyond the type's natural requirement is supported for aggregates.[29]
Attributes, using double-square-bracket syntax [[attr]], offer a standardized, extensible way to provide compiler hints without affecting program semantics. C++11 defined [[noreturn]] to indicate functions that do not return (e.g., [[noreturn]] void exit(int);), enabling optimizations like omitting tail calls, and [[carries_dependency]] to propagate memory dependencies across function boundaries for better concurrency analysis, though implementations vary.
C++11 permits implementations to include non-deterministic garbage collection as an optional feature, provided it adheres to strict safety rules like precise root identification and no interference with undefined behavior. This allowance supports conservative collectors like Boehm GC in environments needing automatic memory management, without mandating it or altering the core language model.
Concurrency and Threading Support
Memory Model and Threading Primitives
C++11 introduced a comprehensive memory model to specify the semantics of concurrent executions, ensuring predictable behavior for multithreaded programs by defining rules for memory visibility, ordering, and atomicity. This model formalizes the happens-before relation, which determines when one memory operation is guaranteed to complete before another becomes visible to other threads, thereby preventing unexpected reorderings by compilers or hardware. Under this model, programs free of data races—concurrent accesses to the same non-atomic memory location where at least one access is a write—exhibit well-defined behavior consistent with a sequential execution. A data race results in undefined behavior, allowing implementations to produce arbitrary outcomes, including crashes or incorrect results.[30] The default memory ordering for atomic operations in C++11 is sequential consistency (std::memory_order_seq_cst), which guarantees that all such operations appear to execute atomically and in a total order that respects the program order within each thread, forming a single global sequence visible to all threads. This strong model simplifies reasoning about concurrency by mimicking the intuitive sequential execution of single-threaded code, though it may impose performance costs on weakly ordered hardware. For more efficient control, C++11 supports weaker orderings via the std::atomic template: acquire ordering on loads ensures that subsequent memory operations in the thread see all prior writes visible to the acquiring thread; release ordering on stores makes all prior writes in the thread visible to subsequent acquires; and relaxed ordering provides only atomicity without synchronization or ordering guarantees, suitable for independent counters. These orderings enable the use of fences (std::atomic_thread_fence) to insert explicit synchronization barriers without associated atomic operations.[30] The std::atomic#include <atomic>
std::atomic<int> counter{0};
// In multiple threads:
++counter; // Atomic increment under sequential consistency by default
#include <atomic>
std::atomic<int> counter{0};
// In multiple threads:
++counter; // Atomic increment under sequential consistency by default
Thread-Local Storage
Thethread_local storage class specifier, introduced in C++11, allows variables to have thread storage duration, ensuring that each thread maintains its own independent instance of the variable. This specifier can be applied to variables at namespace scope, static data members, or local variables with static or thread storage duration, but not to function parameters, return types, or non-static data members. For example, the declaration thread_local int tls_var = 42; creates a unique integer for each thread, initialized to 42 upon first access within that thread.[31][32]
The lifetime of a thread_local variable extends from the first time control passes through its declaration in a thread until the thread terminates, at which point the storage is destroyed if initialization succeeded. This duration is compatible with static storage but scoped to the thread, allowing variables to outlive their enclosing block while remaining thread-isolated. Initialization occurs lazily on a per-thread basis at the point of first use, supporting dynamic initialization if needed, with zero- or constant-initialization potentially happening earlier during program startup. For objects with non-trivial destructors, destruction follows the reverse order of initialization completion within the thread, though no ordering is guaranteed across different threads.[33][32]
Common use cases for thread_local include storing thread-specific identifiers or contexts, such as a unique thread ID for indexing or election algorithms, which avoids the need for synchronization primitives like locks to access shared state. It is also employed in per-thread caches for memory allocators, enabling fast local updates without global contention, as seen in implementations like tcmalloc and jemalloc. Additionally, it supports thread-local logging or state tracking, such as for exception handling or errno, reducing overhead from inter-thread communication. However, accessing thread_local variables incurs a performance cost due to thread-specific allocation and potential indirection, such as calls to runtime functions like __tls_get_addr in dynamic models, though efficient static models (e.g., local-exec) can reduce this to a single instruction. Visibility of changes to thread_local variables across threads relies on the C++ memory model for sequencing guarantees.[34][35]
Standard Library Additions and Changes
Container and Utility Upgrades
C++11 introduced several enhancements to the standard library's containers and utilities, focusing on improved expressiveness, performance, and metaprogramming support for general data handling. These upgrades include fixed-size arrays, singly-linked lists, heterogeneous tuples, hash-based associative containers, type introspection tools, polymorphic function wrappers, and mechanisms for determining callable return types. Such additions addressed limitations in prior standards by providing safer, more efficient alternatives to raw arrays and legacy utilities while enabling advanced template programming. Thestd::array class template, defined in the <array> header, serves as a fixed-size container that encapsulates a C-style array, offering standard container interfaces like begin(), end(), size(), and support for initializer lists. For instance, std::array<int, 3> arr = {1, 2, 3}; initializes the array with the specified values, ensuring bounds safety and compatibility with algorithms without dynamic allocation overhead. This design provides a zero-cost abstraction over built-in arrays, facilitating their use in generic code while avoiding the pitfalls of pointer decay.[36]
Complementing existing sequence containers, std::forward_list, introduced in the <forward_list> header, implements a singly-linked list optimized for efficient insertion and removal at the front or after a given iterator, with constant-time splice operations. Unlike std::list, it omits reverse iterators and bidirectional traversal to reduce memory usage by approximately half, making it suitable for scenarios requiring minimal overhead for forward-only access. Operations like push_front and insert_after execute in amortized constant time, enhancing performance for queues or stacks where backward navigation is unnecessary.
For heterogeneous data storage, std::tuple, from the <tuple> header, generalizes std::pair to hold a fixed number of elements of arbitrary types using variadic templates, as in std::tuple<int, std::string, double> t = std::make_tuple(42, "hello", 3.14);. Access occurs via std::get<i>(t) for zero-based indexing, or std::tie for unpacking into variables, serving as a precursor to structured bindings in later standards. This utility supports uniform initialization for filling tuples and integrates with algorithms for multi-type handling without custom structs.
Hash-based containers, such as std::unordered_map<Key, T, Hash, KeyEqual, Allocator> in the <unordered_map> header, provide unordered associative storage with average O(1) time complexity for lookups, insertions, and deletions using customizable hash functions. For example, std::unordered_map<std::string, int> m; m["key"] = 1; leverages the default hash for strings, enabling efficient key-value mappings in scenarios like caching or symbol tables. These containers, including std::unordered_set, offer reserve operations to control bucket counts and mitigate rehashing costs, with worst-case O(n) performance bounded by load factors.
Metaprogramming received a boost through the <type_traits> header, which supplies a comprehensive set of class templates for compile-time type inspection and manipulation, such as std::is_integral<T> to check if T is an integer type, or std::remove_reference<T> to strip references. These traits enable Substitution Failure Is Not An Error (SFINAE) techniques, allowing templates to select implementations based on type properties, as in conditional enabling of overloads for integral versus floating-point arguments. With over 50 primary, composite, and transformation traits, this facility underpins advanced library design by facilitating type-safe generic programming without runtime checks.
The std::function template, in the <functional> header, acts as a type-erased wrapper for any callable object matching a specified signature, supporting storage of functions, lambdas, or functors in a uniform way. An example is std::function<void(int)> f = [](int x){ std::cout << x; }; f(5);, which enables polymorphic callbacks in event systems or algorithms like std::for_each. It preserves copyability and invocability while introducing small overhead for type erasure, replacing ad-hoc void* or template-heavy alternatives from pre-C++11 code.
To uniformly deduce return types of callables at compile time, std::result_of<Callable(Args...)>::type provides a metafunction that evaluates the invocation expression, handling member functions, functors, and references consistently. For instance, it resolves the return type of a lambda or overloaded function pointer, aiding in perfect forwarding and generic interfaces. This mechanism, while effective in C++11, was refined in C++14 to better handle invalid expressions without undefined behavior.
Threading and Synchronization Facilities
C++11 introduced a comprehensive set of library facilities in the<thread>, <mutex>, <condition_variable>, and <future> headers to support multithreaded programming, enabling developers to create, manage, and synchronize threads in a portable manner. These components build upon the language's memory model to provide safe concurrent execution without relying on platform-specific APIs.
The std::thread class serves as the primary mechanism for launching and managing threads, allowing the execution of callable objects or functions in separate threads of control. A thread object is constructed by passing a callable—such as a function pointer, functor, or lambda expression—along with any arguments, which are copied or moved into the new thread's context; for example:
#include <thread>
void worker() { /* perform work */ }
std::thread t(worker);
t.join(); // Wait for thread completion
#include <thread>
void worker() { /* perform work */ }
std::thread t(worker);
t.join(); // Wait for thread completion
join() block the calling thread until the managed thread completes, while detach() releases ownership without waiting.
Mutual exclusion is facilitated by std::mutex and related RAII wrappers to protect shared data from concurrent access. The basic std::mutex provides exclusive locking via lock() and unlock(), but to prevent resource leaks, std::lock_guard automatically acquires the mutex in its constructor and releases it in its destructor, enforcing the scoped locking idiom; for instance:
#include <mutex>
std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx); // Acquires mutex; releases on scope exit
// [Critical section](/page/Critical_section)
#include <mutex>
std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx); // Acquires mutex; releases on scope exit
// [Critical section](/page/Critical_section)
std::unique_lock supports deferred locking, manual unlocking, and timed operations like try_lock_for(), allowing conditional or timeout-based acquisition without blocking indefinitely.
Condition variables enable threads to wait for specific conditions while avoiding busy-waiting, coordinating via std::condition_variable in conjunction with a std::unique_lock. A waiting thread atomically releases the lock and blocks until notified, then reacquires the lock; predicates can be used to handle spurious wakeups, as in:
#include <condition_variable>
#include <mutex>
std::condition_variable cv;
std::mutex mtx;
bool ready = false;
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // Wait until ready
lock.unlock();
cv.notify_one(); // Or notify_all() for multiple waiters
#include <condition_variable>
#include <mutex>
std::condition_variable cv;
std::mutex mtx;
bool ready = false;
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // Wait until ready
lock.unlock();
cv.notify_one(); // Or notify_all() for multiple waiters
wait_for() or wait_until(), facilitating timeouts in synchronization scenarios.
Asynchronous operations and result passing are handled through std::promise and std::future, which manage a shared state for communicating values or exceptions between threads. A std::promise<T> is set by one thread using set_value() or set_exception(), while the associated std::future<T> retrieves the result via get(), blocking if necessary until ready. The std::async() function simplifies deferred execution by launching a task and returning a future:
#include <future>
auto fut = std::async(std::launch::async, []{ return 42; });
int result = fut.get(); // Blocks and retrieves value
#include <future>
auto fut = std::async(std::launch::async, []{ return 42; });
int result = fut.get(); // Blocks and retrieves value
Smart Pointers and Memory Management
C++11 introduced a suite of smart pointer classes in the<memory> header to automate resource management and reduce the risk of memory leaks, building on the Resource Acquisition Is Initialization (RAII) principle. These pointers provide deterministic deallocation of dynamically allocated objects, replacing the deprecated std::auto_ptr from C++98 and incorporating features from the TR1 technical report, such as reference-counted sharing. Unlike raw pointers, smart pointers ensure that managed resources are released when the pointer goes out of scope or is reset, even in the presence of exceptions.[12][37][5]
The std::unique_ptr class template represents exclusive ownership of a dynamically allocated object, ensuring that only one smart pointer manages it at a time. It is non-copyable but movable, allowing efficient transfer of ownership via move semantics, which aligns with C++11's emphasis on rvalue references for performance. For instance, a std::unique_ptr<int> can be initialized as std::unique_ptr<int> p(new int(5));, and upon destruction or reassignment, it automatically invokes delete on the managed object unless a custom deleter is specified. This design minimizes overhead, with the size of unique_ptr typically matching that of a raw pointer, making it ideal for scenarios requiring single ownership, such as returning resources from factory functions.[12][38][5]
In contrast, std::shared_ptr enables shared ownership through a reference-counting mechanism, where multiple pointers can manage the same object, and it is deleted only when the reference count reaches zero. Initialization is often done via the std::make_shared factory function for efficiency, as in std::shared_ptr<int> sp = std::make_shared<int>(5);, which allocates the object and control block in a single memory block to avoid separate allocations. The reference counting in shared_ptr is atomic, providing thread-safety for concurrent access without additional synchronization in many cases. Custom deleters can be passed to the constructor, such as std::shared_ptr<Resource> res(new Resource, [](Resource* r){ r->close(); delete r; });, allowing management of non-memory resources like file handles. This class directly replaces the TR1 std::tr1::shared_ptr, with improvements including support for array types and better integration with move semantics.[12][39][40]
To address potential circular references that could prevent deallocation in shared ownership scenarios, C++11 provides std::weak_ptr, a non-owning observer of an object managed by std::shared_ptr. A weak_ptr does not increment the reference count, thus avoiding cycles; for example, in a graph structure, nodes can hold weak_ptrs to neighbors while parents use shared_ptrs. Key methods include expired(), which returns true if the managed object has been deleted, and lock(), which attempts to obtain a shared_ptr to the object if it still exists, returning an empty shared_ptr otherwise: if (auto sp = wp.lock()) { /* use sp */ }. Like shared_ptr, weak_ptr supports custom deleters indirectly through the underlying shared_ptr and replaces the TR1 equivalent with enhanced atomic compatibility.[12][41][42]
Custom deleters are a flexible feature across these smart pointers, allowing users to specify arbitrary cleanup logic in the constructor rather than relying on delete. For unique_ptr, the deleter type is a template parameter, enabling compile-time specification: std::unique_ptr<FILE, int(*)(FILE*)> file(fopen("file.txt", "r"), fclose);. Similarly, shared_ptr and weak_ptr accept deleters as runtime arguments, supporting stateful deleters stored in the control block. This extensibility accommodates diverse resources beyond heap memory, such as locking mechanisms or network connections, while maintaining RAII guarantees. The atomic reference counting in shared_ptr ensures safe concurrent decrements and increments, though full thread-safety for the managed object requires additional measures. Overall, these smart pointers form a robust framework for memory management, significantly improving upon pre-C++11 facilities by integrating with the language's move semantics for zero-cost ownership transfers.[12][37][43]
Other Utility Components
C++11 introduced the<random> header, which provides a comprehensive framework for pseudo-random number generation, replacing the older rand() function with more robust and flexible options. This includes random number engines such as std::mt19937, a Mersenne Twister engine known for producing high-quality pseudo-random sequences suitable for non-cryptographic applications. Distributions transform the output of these engines into specific probability distributions; for example, std::uniform_int_distribution generates integers uniformly over a specified range, while std::normal_distribution produces values following a Gaussian distribution with configurable mean and standard deviation. To ensure non-deterministic seeding, std::random_device is provided as a source of true random numbers, often leveraging hardware entropy where available.[1]
The following example demonstrates generating a random integer using std::mt19937 seeded by std::random_device and a uniform distribution:
#include <random>
#include <iostream>
int main() {
std::random_device rd; // Non-deterministic seed source
std::mt19937 gen(rd()); // [Mersenne Twister](/page/Mersenne_Twister) engine
std::uniform_int_distribution<int> dis(1, 6); // Uniform distribution for dice roll
std::cout << dis(gen) << std::endl; // Outputs a random number between 1 and 6
}
#include <random>
#include <iostream>
int main() {
std::random_device rd; // Non-deterministic seed source
std::mt19937 gen(rd()); // [Mersenne Twister](/page/Mersenne_Twister) engine
std::uniform_int_distribution<int> dis(1, 6); // Uniform distribution for dice roll
std::cout << dis(gen) << std::endl; // Outputs a random number between 1 and 6
}
<regex> header adds native support for regular expressions, enabling pattern matching and text processing directly in the standard library. The std::regex class constructs regular expressions, with the default grammar being ECMAScript for broad compatibility. Functions like std::regex_search scan a target string for matches against a pattern, populating a std::smatch object with details such as the matched substrings and capture groups. For instance, std::regex_search(str, matches, pat) returns true if a match is found and stores results in matches. This facility supports operations like validation, extraction, and replacement, with options for case-insensitivity or multiline matching via flags.[1]
An example of email validation using std::regex:
#include <regex>
#include <string>
#include <iostream>
int main() {
std::regex email_pat(R"(\w+@\w+\.\w+)"); // [ECMAScript](/page/ECMAScript) pattern for simple email
std::string email = "[email protected]";
std::smatch matches;
if (std::regex_search(email, matches, email_pat)) {
std::cout << "Valid [email](/page/Email): " << matches[0] << std::endl;
}
}
#include <regex>
#include <string>
#include <iostream>
int main() {
std::regex email_pat(R"(\w+@\w+\.\w+)"); // [ECMAScript](/page/ECMAScript) pattern for simple email
std::string email = "[email protected]";
std::smatch matches;
if (std::regex_search(email, matches, email_pat)) {
std::cout << "Valid [email](/page/Email): " << matches[0] << std::endl;
}
}
<functional> header includes std::reference_wrapper, created via the std::ref helper function, which wraps a reference to an object in a copyable and assignable container. This is particularly useful for passing references to standard algorithms or functors that expect arguments by value, preserving mutability without resorting to pointers. For example, std::ref(x) allows algorithms like std::transform to modify the original object through the wrapper, as the wrapper's get() member returns the underlying reference. It also supports callable invocation via operator().[1]
In the following code, std::ref enables the lambda to be passed by reference to std::for_each, allowing mutation of a captured variable:
#include <functional>
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
int value = 0;
std::vector<int> vec = {1, 2, 3};
auto increment = [&value](int n) { value += n; };
std::for_each(vec.begin(), vec.end(), std::ref(increment));
std::cout << value << std::endl; // Outputs 6
}
#include <functional>
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
int value = 0;
std::vector<int> vec = {1, 2, 3};
auto increment = [&value](int n) { value += n; };
std::for_each(vec.begin(), vec.end(), std::ref(increment));
std::cout << value << std::endl; // Outputs 6
}
<chrono> header introduces types for representing durations and time points, facilitating precise time measurements and arithmetic. std::chrono::duration<Rep, Period> models time intervals as a count of ticks with a compile-time period (a rational fraction), supporting operations like addition and conversion via std::chrono::duration_cast. Predefined types include std::chrono::seconds and std::chrono::milliseconds. Time points, such as std::chrono::time_point<std::chrono::system_clock>, represent instants relative to a clock's epoch, enabling queries like elapsed time.[1]
Example of measuring execution time:
#include <chrono>
#include <iostream>
int main() {
auto start = std::chrono::high_resolution_clock::now();
// Some computation
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Elapsed: " << duration.count() << " ms" << std::endl;
}
#include <chrono>
#include <iostream>
int main() {
auto start = std::chrono::high_resolution_clock::now();
// Some computation
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Elapsed: " << duration.count() << " ms" << std::endl;
}
<ratio> header supports compile-time rational arithmetic through std::ratio<Num, Den>, representing exact fractions like std::ratio<1, 60> for minutes in an hour. Alias templates such as std::ratio_add and std::ratio_multiply perform operations at compile time, underpinning <chrono> periods and ensuring type-safe fraction handling without runtime overhead.[44][1]
Compatibility and Deprecations
Improvements for C Compatibility
C++11 introduced several enhancements to improve interoperability with C code, particularly by refining type definitions and library support to align more closely with C99 features while maintaining binary compatibility for shared data structures. These changes ensure that C++ programs can more seamlessly interface with C libraries through foreign function interfaces (FFI), without introducing new incompatibilities that would break existing C/C++ integrations.[45] One key improvement involves the revision of Plain Old Data (POD) types, which were split into two distinct categories: trivial types and standard-layout types. Standard-layout types guarantee a memory layout compatible with C structs, allowing C++ classes to be used in contexts where C expects plain data structures, such as when passing aggregates across language boundaries. This relaxation broadens the set of types that can be safely shared with C code, as long as they meet the standard-layout criteria—no virtual bases, no non-static data members of reference or non-standard-layout types, and consistent access specifiers across bases. For example, a simple struct with public members and no user-provided constructors qualifies as standard-layout, enabling direct use in C functions without padding or alignment discrepancies.[46] The inclusion of fixed-width integer types via the new<cstdint> header further enhances C compatibility by adopting C99's <stdint.h> definitions directly into the C++ standard library. Types such as int32_t, uint64_t, and int_least16_t provide exact or minimum bit widths with specified signedness, ensuring portable integer representations across platforms when interfacing with C APIs that rely on these for serialization or hardware interaction. This alignment eliminates the need for custom typedefs in mixed-language projects and supports C99's guarantees for integer literals and formatting, such as INT32_C(42). (Note: The latter is the C99 standard ISO/IEC 9899:1999, referenced in C++11 §18.3 for <cstdint> adoption.)
Unrestricted unions represent another advancement, permitting non-POD class types as members under controlled conditions, but crucially maintaining full compatibility with C unions when the union itself is a POD type. In such cases, the union's layout remains identical to a C union, with active member tracking handled only in C++ contexts, avoiding any runtime overhead or binary differences for C-interoperable scenarios. This allows C++ developers to extend unions for internal use while preserving seamless data sharing, such as in variant-like structures passed to C routines.[47]
The extern "C" linkage specification remains unchanged from prior standards but receives clarifications in C++11 to better support mixing C and C++ code, including explicit rules for function types and pointers under C linkage. This ensures that declarations wrapped in extern "C" blocks produce unmangled names and compatible calling conventions, facilitating direct calls to C functions from C++ without additional wrappers. No new restrictions were imposed, preserving the ability to compile C headers in C++ environments. (C++11 standard draft, §7.5 for language linkage.)
Overall, these modifications were designed to introduce no new incompatibilities with C, allowing existing C codebases to integrate with C++11 binaries via standard mechanisms like shared libraries, thereby supporting gradual adoption in legacy systems.[48]
Removed or Deprecated Features
In C++11, several features from prior standards were removed or deprecated to streamline the language, reduce complexity, and eliminate underutilized or problematic elements. One significant removal was theexport keyword, originally introduced in C++98 to enable separate compilation of template definitions. Due to its high implementation complexity and lack of broad compiler support, the feature was entirely removed in C++11, freeing the keyword for potential future use.[49]
The pre-C++11 usage of the auto keyword as a storage class specifier—indicating automatic storage duration for variables, equivalent to the default—was removed in favor of repurposing auto for automatic type deduction based on initializer expressions. This change eliminated redundancy, as automatic storage is now implicit for local variables, and prevented confusion with the new type-deduction semantics. For example, declarations like auto int x = 42; became ill-formed, requiring simply int x = 42; or the new auto x = 42; for deduction.[50]
The register keyword, which suggested to the compiler that a variable should be stored in a CPU register for faster access, was deprecated in C++11. Modern compilers already perform such optimizations automatically, rendering the hint obsolete and potentially misleading. Its use still compiled but triggered warnings, and it was fully removed in C++17.
Dynamic exception specifications, such as void f() throw(int, std::bad_alloc);, which specified the exceptions a function could throw, were deprecated in C++11. These specifications were unreliable for runtime enforcement and interacted poorly with the new exception-handling model, leading to their replacement by the noexcept specifier for compile-time guarantees. They were removed entirely in C++17.
Regarding bit-fields, C++11 removed any special treatment of the volatile qualifier in terms of access granularity; accesses to volatile bit-fields now follow the general volatile rules, where the size and alignment of accesses are implementation-defined rather than guaranteeing bit-level operations. This aligned volatile semantics more closely with the new memory model but could affect low-level hardware interactions.
C++11 also deprecated several legacy C library functions in the standard library, such as std::gets in <cstdio>, due to security vulnerabilities and obsolescence; safer alternatives like std::fgets were encouraged. While the C-style headers (e.g., <stdio.h>) remained available for compatibility, their use was discouraged in favor of the C++-specific versions (e.g., <cstdio>), continuing a deprecation trend from C++98. No major language features were outright removed beyond the noted cases, though compilers often issued warnings for old-style C casts like (int)ptr to promote safer, explicit casts such as static_cast<int>(ptr).
