6. Loop: range-based
• for (int i = 0; i < v.size(); ++i) // bad
• cout << v[i] << 'n';
• for (auto p = v.begin(); p != v.end(); ++p) // bad
• cout << *p << 'n';
• Constructs that cannot overflow do not overflow (and usually run faster):
• for (auto& x : v) // range-based for,
• cout << x << 'n';
• for (int i = 1; i < v.size(); ++i) // 无法使用 range-for, 因为需要2个元素
• cout << v[i] + v[i - 1] << 'n';
• for (int i = 0; i < v.size(); ++i) // v.size可能改变, 所以range-based for可能无法使用
• cout << f(v, &v[i]) << 'n';
8. Strongly typed enum
• 不能与int互相转换 (类型安全)
– enum Color {R, G, B}; // before c++11
– enum class Color {R, G, B}; // strongly typed
– Color c = Color::R;
– if (0 == c) // Error: cannot convert
– if (0 == static_cast<int>(c)) // ok
9. Raw string literals
• 不用escape特殊字符
– string raw_pattern=R"((+|-)?[[:digit:]]+)";
– string s = R"(This is the first line
– And this is the second line)“; //多行
– string cmd(R”(ls –l /home”));
– UTF支持, UR(“...”)
10. 初始化
• 一些例子
– int array[] = { 1, 2, 3 };
– std::vector v = { 1, 2, 3};
– std::map m = { {1, 2}, {2, 3} };
– struct Point {int x; int y;}
– Point p = {1, 2}; // ok
– std::vector f() { return {1, 2, 3} ;} // ok
– void f(std::vector<int> v);
– f({1, 2, 3}) // ok
• 对于struct, 按照顺序初始化各成员
• 对于class, 如果有用户定义的constructor, 那么{}调用constructor, 没有的话参考
上条
• 另外, 增加了in class initialization
– // in header file .H
– class Fun {
– public:
– int x = 0; // ok
– static constexpr int arr [4] = { 1, 2, 3, 4}; // also ok, 静态的话需要加上constexpr
11. 初始化:delegating
• Delegating构造函数: 在一个构造函数里调用另一个
– 防止代码重复
• class Date {
• int d;
• Month m;
• int y;
• public:
• Date(int ii, Month mm, year yy)
• :i{ii}, m{mm} y{yy}
• { if (!valid(i, m, y)) throw Bad_date{}; }
• Date(int ii, Month mm)
• :Date{ii, mm, current_year()} {}
• // ...
• };
12. using, static_assert
• using基本和typedef一样, 除了在模板中略有区别
– typedef std::unordered_map<int, int> MyMap;
– using MyMap = std::unordered_map<int, int>;
– using CallBackFunc = void(*)(int);
• class Rec {
• // ... data and lots of nice constructors ...
• };
• class Oper : public Rec {
• using Rec::Rec; // 构造函数同基类一样, 所以不必要再写一遍, 保证没有其他需要初始化的成员
• // ... no data members ...
• };
• static_assert:编译期检查
– static_assert(sizeof(long) >= 8, "64-bit code generation required for this library.");
– constexpr int version = 5;
– static_assert(version > 1, “version wrong”);
– static_assert(std::is_base_of<MyBase, T>::value, "T must be derived from MyBase");
– static_assert(std::is_default_constructible<T>::value, “T does not have default constructor”);
13. constexpr
• constexpr: 表达式编译期求值 // not only const
– constexpr int size=10; // vs: const int size = 10;
– int A[size]; // not ok with const
– constexpr bool master = false;
– template <bool B> void switchToMaster();
– switchToMaster<master>(); // not ok with const;
– constexpr还可以用在function:
• constexpr int min(int x, int y) { return x < y ? x : y; }
• constexpr int m2 = min(-1, 2); // compile-time evaluation
• int m3 = min(-1, v); // run-time evaluation
• constexpr不保证在编译时期求值
• 不要将所有的函数声明为constexpr, 确定是否可以在编译时求值
• constexpr隐含inline
14. noexcept
• 如果函数不会抛出异常, 或者函数无法处理异常, 那么申
明为noexcept
– bool func(int size) noexcept { // no throw, and not expecting
exception inside the function
– vector<int> vec(size); // this may throw
– return true;
– }
– 如果noexcept的函数内throw了异常, 那么std::terminate()将被
调用
– 析构函数应当不抛出异常, 所以默认析构函数隐含noexcept,
如果类所有成员的析构函数是noexcept的
– 有助于编译器优化代码执行路径
– constexpr函数隐含noexcept
– swap/move函数应当同样不抛出异常
17. lambda
• [ capture-list ] ( params ) { body }
– 效果相当于一个functor
– 因为有时候, 一些std的函数需要提供一个functor来作为参数, 比如
std::for_each, 而你写一个functor的话也就这一个地方用到了,
lambda就是为了简化这种过程, 相当于in place一个functor
– 一些例子:
• std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ })
– []: capture list, lambda内如果需要用一些外面的变量的话
• [x]: capture by value
• [&x]: capture by reference
• [&]: capture any by reference
• [=]: capture any by value
• [this]: capture class members
• [=, &x]: by value, except for x (by reference)
– 返回值由编译器推定,也可以指定
• [](int)->bool { /* do something here*/ })
18. lambda
• 可以用作初始化变量
– 例如,比较复杂的,或者const变量
• const string var = [&]{
• if (!in) return ""; // default
• string s;
• for (char c : in >> c)
• s += toupper(c);
• return s;
• }();
19. move
• lvalue, rvalue, xvalue, glvalue
– lvalue: (这样叫的原因是它能出现在=的左边)
• With identy, cannot be moved from
– prvalue:
• Without identy, can be moved from
– xvalue:
• With identy, can be moved from
– glvaue:
• lvalue or xvalue
– rvalue:
• prvalue or xvalue
int prvalue();
int& lvalue();
int&& xvalue();
20. move
• std::move()
– 这个函数并不move任何东西
– 它实际上返回一个&& (rvalue reference)
– 避免对lvalue作std::move(), 会遗留下一个处于无效状态的对象,如果之后使用的话?
• void f() {
• string s1 = “sss";
• string s2 = s1; // copy
• assert(s1 == “sss");
• // bad, if you want to keep using s1's value
• string s3 = move(s1); // s1可能无效了
• // s1可能改变了
• assert(s1 == "supercalifragilisticexpialidocious");
• }
• template<class T>
• void swap(T& a, T& b) {
• T tmp = move(a); // could invalidate a
• a = move(b); // could invalidate b
• b = move(tmp); // could invalidate tmp
• }
• IoBuf createBuffer(); //return is rvalue
• IoBuf& mybuffer = createBuffer(); // now moved from return object (temporary), no copy!