C++11 语言新特性(New features of C + + 11 language)

1. nullptr 和 std::nullptr_t

  • C++11 允许你使用 nullptr 取代 0或NULL
  • 这个新特性特别能够帮助你在 “NULL 指针被解释为一个整数值”时避免误解
  • nullptr 是个新关键字,它被 自动转换为各种指针类型,但不会被转换为任何整数类型

例如:

void f(int);
void f(void*);

f(0);       // call f(int)
f(NULL);    // call f(int) if NULL is 0
f(nullptr); // call f(void*) 

2. 以 auto 完成类型自动推导

  • C++11 允许你声明一个变量或对象而不需要指明其类型,但一定需要一个初始化操作
auto i = 42; // i -> int
double f();
auto d = f(); // d --> double
  • 可以为 auto 声明的变量加上额外的限定符
static auto vat = 1.1;
  • 通常 auto 在类型很长或表达式很负责时,特别有用,例如:
// 迭代器
std::vector<std::string> vecStr;
auto pos = vecStr.begin(); // 通常 std::vector<std::string>::iterator
...
// lambda
auto f = [] (int x) -> bool {return false;};

3. 一致性初始化与初值列

  • 一致性初始化,面对任何初始化动作你可以使用相同语法,也就是使用大括号,例如:
int values[] {1, 2, 3, 4, 5};
std::vector<int> v {1, 2, 3, 4, 5};
std::vector<std::string> cities {"beijing", "shanghai"};
  • 初值列会强迫造成所谓值初始化,意思是即使某个 local 变量属于某种基础类型(通常会有不明确的初值)也会被初始化为0或 nullptr
int i;    // i 可能是个随机值
int j{};  // j 被初始化成 0
int* p;   // p 可能是个随机值
int* q{}; // q 会被初始化成 nullptr
bool b{}; // b 被初始化成 0
  • 支持“用户自定义类型之初值列”的概念,提供 std::initializer_list<>,用来支持以一系列值进行的初始化,或者想处理一系列的值,例如:
void print(std::initializer_list<int> vals) {
    for (auto v : vals) {
        std::cout << v << std::endl;
    }
}
print({ 1,2,3,4,4,5,6,7 });

4. range-based for 循环

  • 一种崭新的 for 循环形式,可以逐一迭代某个给定的区间、数组、集合内的每一个元素,一般语法如下:
// decl是给定的 coll 集合中的每个元素的声明,针对这些元素,给定的 statement 会被执行。
for ( decl : coll ) {
    statement
}
// 常规遍历
for (int i : {1, 2, 3, 4, 5}) {
    std::cout << i << std::endl;
}
// 修改元素值,vector每个元素乘以3
std::vector<double> vecD;
...
for (auto& elem : vecD) {
    elem *= 3;
}
// 建议的写法,可以避免调用每个元素的拷贝构造函数和析构函数
template <typename T>
void PrintElements(const T& coll) {
    for (const auto& elem : coll) {
        std::cout << elem << std::endl;
    }
}

5. Move语义和右值引用

  • C++11 一个最重要的特性就是支持 Move 语义,用于避免非必要的拷贝和临时对象
  • std::move() 自身并不做任何moving的工作,它只是将其实参转换成一个所谓的右值引用,那是一种被声明为 T&& 的类型
  • T&& 右值,一个对象被标记为右值,就可以认为它是一个不在被需要的(临时)对象,std::move(T),所以你可以直接拿这个对象中的数据,如对象中重要数据的地址
  • 对于 class 可以实现 move 构造函数,用于实现 move 的语义化,例如 ClassA(T&& x); 当我们使用 ClassA(std::move(T))的时候,就会执行该 move 构造函数
  • 通常,若类中不存在 move 构造函数,拷贝构造函数就会被用上
  • C++ 标准库的 class 保证了,在一次 move 之后,对象处于有效但不确定的状态,也就是说你可以在 move 之后对他赋予新值,但当前值是不确定的
  • STL 容器保证了,在一次 move 之后,被 move 的对象,其值为空

6. 新式的字符串字面量

  • 原始字符串(raw string),以 R(“开头,以”)结尾,可以内包含line break,例如:
// 常规,两个反斜杠和一个n
"\\\\n"
// raw string
R("\\n")
  • 原始字符串对于定义正则表达式特别有用
  • 编码前缀,可以给字符串字面量定义一个特殊的字符编码前缀,如下:
// u8 定义一个 UTF-8 编码,字符串类型为 const char[N]
auto u8 = u8"你好";

// u 定义一个 UTF-16 编码,字符串类型为 const char16_t[N]
auto u = u"你好";

// U 定义一个 UTF-32 编码,字符串类型为 const char16_t[N]
auto U = U"你好";

// L 定义一个宽字符串字面量,字符串类型为 const wchar_t[N]
auto L = L"你好";

7. 关键字 noexcept

  • C++11 提供了关键字noexcept,用来指明某个函数 无法 或 不打算 抛出异常,例如:
void foo() noexcept;
  • 可以在 noexcept(…) 中指定一个Boolean条件,若符合条件就不抛出异常,通常指明使用 noexcept 而不带条件,其实就是 noexcept(true) 的一个简洁形式

8. 关键字 constexpr

  • C++11 ,可以使用 constexpr 让表达式的结果确定在代码编译过程中,例如
constexpr int square(int x) {
    return x*x;
}

float a[square(9)]; // a 有81个元素,在代码编译过程中就计算好了
————————

1. nullptr 和 std::nullptr_t

  • C++11 允许你使用 nullptr 取代 0或NULL
  • This new feature can especially help you avoid misunderstanding when “null pointer is interpreted as an integer value”
  • Nullptr is a new keyword that is automatically converted to various pointer types, but not to any integer type

For example:

void f(int);
void f(void*);

f(0);       // call f(int)
f(NULL);    // call f(int) if NULL is 0
f(nullptr); // call f(void*) 

2. Complete type automatic derivation with auto

  • C + + 11 allows you to declare a variable or object without specifying its type, but it must require an initialization operation
auto i = 42; // i -> int
double f();
auto d = f(); // d --> double
  • You can add additional qualifiers to variables declared by auto
static auto vat = 1.1;
  • Usually, auto is especially useful when the type is very long or the expression is very responsible, for example:
// 迭代器
std::vector<std::string> vecStr;
auto pos = vecStr.begin(); // 通常 std::vector<std::string>::iterator
...
// lambda
auto f = [] (int x) -> bool {return false;};

3. Consistency initialization and initial value column

  • Consistent initialization. You can use the same syntax for any initialization action, that is, curly braces, for example:
int values[] {1, 2, 3, 4, 5};
std::vector<int> v {1, 2, 3, 4, 5};
std::vector<std::string> cities {"beijing", "shanghai"};
  • The initial value column will force the so-called value initialization, which means that even if a local variable belongs to a basic type (usually has an ambiguous initial value), it will be initialized to 0 or nullptr
int i;    // i 可能是个随机值
int j{};  // j 被初始化成 0
int* p;   // p 可能是个随机值
int* q{}; // q 会被初始化成 nullptr
bool b{}; // b 被初始化成 0
  • The concept of “initial value column of user defined type” is supported, and STD:: initializer is provided_ List < >, used to support initialization with a series of values, or to process a series of values, for example:
void print(std::initializer_list<int> vals) {
    for (auto v : vals) {
        std::cout << v << std::endl;
    }
}
print({ 1,2,3,4,4,5,6,7 });

4. range-based for 循环

  • A new form of for loop, which can iterate each element in a given interval, array and set one by one. The general syntax is as follows:
// decl是给定的 coll 集合中的每个元素的声明,针对这些元素,给定的 statement 会被执行。
for ( decl : coll ) {
    statement
}
// 常规遍历
for (int i : {1, 2, 3, 4, 5}) {
    std::cout << i << std::endl;
}
// 修改元素值,vector每个元素乘以3
std::vector<double> vecD;
...
for (auto& elem : vecD) {
    elem *= 3;
}
// 建议的写法,可以避免调用每个元素的拷贝构造函数和析构函数
template <typename T>
void PrintElements(const T& coll) {
    for (const auto& elem : coll) {
        std::cout << elem << std::endl;
    }
}

5. Move semantics and right value reference

  • One of the most important features of C + + 11 is the support of move semantics, which is used to avoid unnecessary copies and temporary objects
  • STD:: move () itself does not do any moving work. It just converts its parameters into a so-called right value reference, which is a type declared as T & &
  • T & & R-value. When an object is marked as R-value, it can be considered as an unwanted (temporary) object, STD:: move (T), so you can directly take the data in the object, such as the address of important data in the object
  • For class, the move constructor can be implemented to realize the semantics of move, such as classA (t&& x); When we use classA (STD:: move (T)), the move constructor will be executed
  • Usually, if move constructor does not exist in class, copy constructor will be used
  • The class of C + + standard library ensures that after a move, the object is in a valid but uncertain state, that is, you can give it a new value after the move, but the current value is uncertain
  • The STL container ensures that after a move, the value of the moved object is null

6. New string literal

  • Raw string, which ends with R (“start with”), can contain line break, for example:
// 常规,两个反斜杠和一个n
"\\\\n"
// raw string
R("\\n")
  • Raw strings are particularly useful for defining regular expressions
  • Encoding prefix: you can define a special character encoding prefix for string literals, as follows:
// u8 定义一个 UTF-8 编码,字符串类型为 const char[N]
auto u8 = u8"你好";

// u 定义一个 UTF-16 编码,字符串类型为 const char16_t[N]
auto u = u"你好";

// U 定义一个 UTF-32 编码,字符串类型为 const char16_t[N]
auto U = U"你好";

// L 定义一个宽字符串字面量,字符串类型为 const wchar_t[N]
auto L = L"你好";

7. 关键字 noexcept

  • C + + 11 provides the keyword noexcept to indicate that a function cannot or does not intend to throw an exception, for example:
void foo() noexcept;
  • You can specify a Boolean condition in noexcept (…). If the condition is met, no exception will be thrown. It usually indicates that noexcept is used without conditions. In fact, it is a concise form of noexcept (true)

8. 关键字 constexpr

  • In C + + 11, you can use constexpr to determine the result of the expression during code compilation, for example
constexpr int square(int x) {
    return x*x;
}

float a[square(9)]; // a 有81个元素,在代码编译过程中就计算好了