SlideShare a Scribd company logo
1 of 51
cpp11
罗培恩
Agenda
• 基本特性
– auto, loop, raw string, unicode, nullptr, initialization,
default/delete, static_assert, constexpr, lambda,
variadic template, move, ...
• 多线程
– thread, async, future, promise, atomics, mutex, lock,
condition var, thread_local, ...
• 标准库
– shared_ptr, unique_ptr, unordered_map/set, tuple,
regex, function, bind, time, ...
基本特性
auto, decltype
• auto: 类型声明
– auto i = 10;
– auto iter = vec.begin();
– 可以和const, pointer, reference, volatile一起使用
• auto& n = i;
• auto* pi = &i;
• const auto d = i;
• decltype: 变量推断类型
– int i; decltype(i) i2 = i; // 等同于 auto i2 = i;
– 主要用在template里, 方便书写
• template<typename T, typename S>
• auto multiply(T lhs, S rhs) -> decltype(lhs * rhs) { return lhs * rhs; }
Loop:range-based
• 用于所有的stl标准容器
• 数组, 初始化列表
• UDT: 要求begin(), end()提供有效的遍历
• for (const auto& e : vec) { //const&避免copy
• cout << e << “n”;
• }
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';
nullptr
• 表示一个空指针
– int* p = nullptr;
– if (p == NULL) { ... } // still works
• 类型安全: nullptr是一个指针, 不是其他
– void f(char const *ptr);
– void f(int v);
– f(NULL); // calls f(int v)
– f(nullptr); // calls f(char const* ptr)
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
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(“...”)
初始化
• 一些例子
– 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
初始化: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()} {}
• // ...
• };
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”);
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
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函数应当同样不抛出异常
delete/default
• delete: 申明的函数不可被调用
– 举例:基类中阻止copy constructor:防止slicing
• class B { // GOOD: base class suppresses copying
• B(const B&) = delete;
• B& operator=(const B&) = delete;
• virtual unique_ptr<B> clone() { return /* B object */; }
• // ...
• };
• default: 使用编译器默认产生的函数
• class Tracer {
• string message;
• public:
• Tracer(const string& m) : message{m} { cerr << "entering " << message << 'n'; }
• ~Tracer() { cerr << "exiting " << message << 'n'; }
• Tracer(const Tracer&) = default;
• Tracer& operator=(const Tracer&) = default;
• Tracer(Tracer&&) = default;
• Tracer& operator=(Tracer&&) = default;
• };
override/final
• 虚函数, 在申明的时候使用virtual/override/final三者之一:
– virtual: 当申明一个新的虚函数
– override: 当需要复写一个虚函数
– final: 不可再被复写
• struct B {
• void f1(int);
• virtual void f2(int) const;
• virtual void f3(int);
• // ...
• };
• struct D : B {
• void f1(int); // warn: D::f1() hides B::f1()
• void f2(int) const; // warn: no explicit override
• void f3(double); // warn: D::f3() hides B::f3()
• // ...
• };
• struct D2 : B {
• virtual void f2(int) final; // BAD; pitfall, D2::f2 does not override B::f2
• };
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*/ })
lambda
• 可以用作初始化变量
– 例如,比较复杂的,或者const变量
• const string var = [&]{
• if (!in) return ""; // default
• string s;
• for (char c : in >> c)
• s += toupper(c);
• return s;
• }();
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();
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!
move
• move constructor/assigment
– 增加效率,copy代价可能太高
– 我们有时候并不需要copy, 比如我们只想保留使用其中一个,例如其中一个是临时的对象
– class_name ( class_name && )
– class_name & operator=(class_name && other)
– 一个例子:
• IoBuf(IoBuf&& other) {
• _data = other._data;
• _length = other._length;
• other._data = nullptr;// 让other这个临时对象无效
• other._length = 0; // 不然othter的destructor会delete _data!
• }
• IoBuf& operator=(IoBuf&& other) {
• if (this != &other) {
• delete[] _data;
• _data = other._data;
• _length = other._length;
• other._data = nullptr;// 让other这个临时对象无效
• other._length = 0; // 不然othter的destructor会delete _data!
• }
• }
Variadic template
• 可变参数模板
– 模板参数的个数可变的情形
– template <typename... T>
– 通常和递归模板结合
– 举例:printf
– 举例:QA想测试函数的时间开销,但不同函
数的参数都不相同
– 举例:遍历数组
Variadic template
Variadic template
多线程
多线程
• c++11之前
– Boost thread (和c++11 thread差不多)
– libpthread, openmp, mpi
– 公司内部各种线程库
• C++11
– Thread: 独立的可执行单元
– Mutex: 共享数据的访问控制
– conditional_variable: block-until-true execution
– future, async: 异步调用
– Atomic: 原子性访问操作
pthread vs std::thread
• pthread是C函数库
– 设计没有覆盖有关C++的问题
• 对象生命周期
• Exception
– pthread_cancel没有类似的c++功能
• std::thread
– 作为线程执行的抽象
– 提供了一组其他类来管理线程执行中的问题
• Mutex
• Conditional_variable
• Lock
– 提供了丰富的创建可调用对象(callable)的函数,如lamda
– RAII作为设计的核心思想,管理线程资源(lock, mutex)
std::thread
• 接受任何可调用的对象, 异步方式运行
– std::thread(func, arg1, arg2, ..., argN);
– func: 可以lamda, functor, 函数指针
– E.g.: std::thread t([]{std::cout << “hello world.n”});
– 主要方法
• Join()
– main退出的时候,所有运行中的线程都应先join(),不然退出会造成undefined behavior
– 如果一个thread变量在销毁前没有join()/detach(),也会造成可能的crash
• Detach()
• Get_id()
• std:thread::get_hardware_concurrency()
– 数据共享问题避免
• Pass by value (多个线程使用同一份数据,考虑copy)
• 保证共享的数据其生命周期比线程更久
– 异常
• 永远不要把异常抛出std::thread外,这样会导致undefined behavior
• 线程安全:在线程内接住处理所有异常
std::thread
• 保证共享的数据其生命周期比线程更久
async, future
• std::async
– 用来构造std::future的一个函数模版,用来异步执
行一个函数,支持两种launch policy:
– std::launch::async
• 产生一个新的线程来运行
– std::launch::deferred
• 在当前线程中运行
– 适合debug
– 在future.get()的时候运行
• std::future
– 用来表示async返回结果的一个类
– 允许异常或者value作为返回结果
async, future
• 如何获得执行结果
– future.get()
• 等待直到函数执行结束返回
• 返回值通过move/copy取得
• 可以是std::future<void>,如果没有返回值
– 除了get(),还有wait()
• 等待执行结束
• 可以指定等待timeout(比如万一函数执行过长怎么办)
promise, packaged_task
• std::packaged_task
– async提供了高level的异步调用, packaged_task和promise相当于低level的实
现
– packaged_task是一个可调用对象(类似std::function)
• void operator()
– promise.set_value(fn(std::forward<Ts>(ts)...)); // fulfill the promise
– 提供了获得调用结果的接口
• std::future<std::string> get_future()
• std::promise<T>
– future的provider
– 相当于连接future和packaged_task
– asnync的工作相当于:
• promise<int> intPromise; // 创建promise
• future<int> intFuture = intPromise.get_future();
• std::thread t(asyncFunc, std::move(intPromise)); // or packaged_task
• result = intFuture.get(); // may throw MyException
mutex
• 多种类型
– std::mutex
– std::timed_mutex
– std::recursive_mutex;
– std::recursive_timed_mutex
• recursive_mutex
– 同一个线程内可以反复lock: 多次lock不会死锁
• Recursive mutex ownership属于上锁的线程, 只有这个线程才能
unlock, 其他线程不可以(不同于mutex, 可以由另一个线程
unlock)
– 其他线程则会在lock时等待
– 一个线程lock了n次, 必须unlock n次才能解锁
mutex
• Recursive mutex
– void foo()
– {
– ... mutex_acquire();
– ... foo(); // 递归调用, 不用recursive mutex会死锁
– ... mutex_release();
– }
• 通常情况下, 应避免使用recursive_mutex, 考虑
其他设计
mutex
• Lock (block)
– 对mutex上锁, 如果mutex已被lock, 那么阻塞在那里(non
recursive mutex)
• Unlock
– 对mutex解锁
• Try_lock (fail)
– 试图mutex加锁, 如果无法上锁, 则返回false(和lock的区别在
于try_lock始终是非阻塞的)
• Try_lock_for (timed_mutex)
– 试图在给定的时间(std::chrono::duration)内加锁, 如果不成功
则在duration后返回false, 否则在加锁时刻返回true
• Try_lock_until (timed_mutex)
– Std::chrono::time_point
mutex
• timed_mutex
– 当某个线程必须每隔一定时间做一件事情的时候
– 当某个线程在给定的时间内必须完成一件事情的时
候
void recover_task() {
// acquire imtx.lock
std::future<bool> result = std::async(recover_from_disk());
if (imtx.try_lock_for(std::chrono::milliseconds(1000)) {
std::cout << "recover done.n";
} else {
std::cout << "oops, recovery not finisned in 1s, check
recover status.n";
}
}
lock
• RAII wrapper of mutex
– 在构造函数里对mutex上锁,析构的时候解锁
– std::lock_guard vs. std::unique_lock
• unique_lock提供了unlock()方法
• lock_guard没有unlock()可供调用,在析构的时候自动释
放
• std::lock
– 对多个lockable object上锁
• std::unique_lock<std::mutex> l1(m1, std::defer_lock);
std::unique_lock<std::mutex> l2(m2, std::defer_lock);
std::lock(l1, l2);
conditional_variable
• 提供了一种多线程间同步的机制
– 用来阻塞一个或多个线程的执行, 直到另一个线程改变一个共享的变量条
件并通知阻塞等待的线程
– 可以用来作为事件通知机制
– 通常需要:
• conditional_variable
• mutex
• shared variable (boolean)
– 线程1:
• 获得mutex
• 修改共享的条件变量
• 通知等待线程 (notify(), notify_all())
– 线程2:
• 获得mutex
• 等待(wait()), 阻塞执行
• wait() = while(!pred()) { wait(lock); }
• 等待结束的时候mutex自动获得, 检查共享的条件变量, 决定干活还是继续等
• Lost notification = dead lock!
conditional_variable
• 例子
conditional_variable
• Producer-consumer
标准库
智能指针
• Shared_ptr
– 引用计数实现
– 当引用计数减到0的时候, 自动销毁对象
– E.g.:
• std::shared_ptr<int> p(new int); // alloc int + mgr obj
• auto p = std::make_shared<int>(); // prefer, 少一次内存分配
• Unique_ptr
– 管理动态产生的内存对象, 提供显式的ownership语义, 推荐使用让代码更卫生
• Weak_ptr
智能指针
• shared_ptr实现
智能指针
• 当对象分配产生, 并有第一个shared_ptr指向它的时候
– shared_ptr的构造函数生成一个manager object, manager
object存放ref count(shared count和weak count), 并且有真正
指向对象的指针
– shared count纪录多少个shared_ptr指向那个manager object,
weak count纪录多少个weak_ptr指向那个manager object
– 一开始, shared_count = 1, weak count = 0
– 当新的shared_ptr/weak_ptr指向此manager object时候,
++count
– 当shared_ptr销毁或者指向其他的时候, --shared count
– 当shared count减到0的时候, delete那个managed object(注意
不是manager object)
• 如果此时weak count = 0, 那么删除manager object
• 如果此时weak count > 0, 那么保留manager object
容器
• array:内存连续
– Fixed size(vs. vector), random access
– E.g.:array<int,6> a = { 1, 2, 3 };
• forward_list: singly linked list
– 内存开销少
– 没有size()
• unordered_map/multimap:
– 基于hash, 查询/插入/删除O(1)
• unordered_set/multiset
tuple
• 保存不同类型的对象
– 类似std::pair, 不过可以有任意个
• tuple<string,int,double,int> info(“string",2,3.14,82);
• get(X)获得tuple中第X个对象, auto s = get<0> info;
• 或者用tie: tie(s,a,b,c) = info;
– 用途
• 返回多个对象
– std::tuple<int, std::string> func();
– tie(err_code, err_msg) = func();
• 方便利用模板(和variadic template配合)
regex
• <regex>
– 构造regular expression, 语法支持多种选项
• ECMAScript: (preferred)
– http://www.cplusplus.com/reference/regex/ECMAScript/
• basic:
– POSIX
• extended
– extended POSIX
• awk, grep, egrep, ...
– http://en.cppreference.com/w/cpp/regex/syntax_option_type
• 构造一个regex可能是耗时的,如果expression不变反复使用,那么最好作为一个静态的变量构造
一次
– match:
• std::regex_match: 是否字符串完全匹配pattern
– search:
• Find one:
– std::regex_search:是否含有子串匹配pattern
• Find all:
– std::cregex_iterator, std::sregex_iterator, std::wcregex_iterator, std::wsregex_iterator
– replace:
• std::regex_replace:返回一份字符串的copy, 替换其中所有匹配的字串
regex
• 例子
– search
– replace
function
• store/copy/invoke
– function, 函数指针
– lamda表达式
– bind表达式
– functor
• 比函数指针强大
– 能捕获local变量
– 能调用类函数 (capture *this)
• void (*callbackFunc)(int);
• std::function< void(int) > callbackFunc; //preferred
chrono
• Time point
– 以距离epoch的duration表示
• Duration:时间间隔
– 一些预定义的时间间隔包括
• std::chrono::nanoseconds
• std::chrono::microseconds
• std::chrono::milliseconds
• std::chrono::seconds
• std::chrono::minutes
• std::chrono::hours
• Clock
– 三种类型,按照ISO
• system_clock:system wall clock,例如可能随DST改变
• steady_clock:time point随着物理时间以相同的速度增加,不会减少
• high_resolution_clock:系统提供的最小tick的时钟
– 实际上,gcc实现三者没有区别
• typedef system_clock steady_clock;
• typedef system_clock high_resolution_clock;
chrono
• 例子
– std::chrono::duration<int,std::ratio<60*60*24> > one_day (1);//1天=60*60*24秒
–
– system_clock::time_point today = system_clock::now();
– system_clock::time_point tomorrow = today + one_day;
– typedef std::chrono::high_resolution_clock clock;
– typedef std::chrono::milliseconds milliseconds;
–
– clock::time_point t0 = clock::now();
– // ... some operation to time estimate
– clock::time_point t1 = clock::now();
–
– milliseconds total_ms = std::chrono::duration_cast<milliseconds>(t1 - t0);

More Related Content

What's hot

The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)jeffz
 
Wind.js无障碍调试与排错
Wind.js无障碍调试与排错Wind.js无障碍调试与排错
Wind.js无障碍调试与排错jeffz
 
ajax_onlinemad
ajax_onlinemadajax_onlinemad
ajax_onlinemadKitor23
 
Node.js 异步任务的四种模式
Node.js 异步任务的四种模式Node.js 异步任务的四种模式
Node.js 异步任务的四种模式Stackia Jia
 
從 Singleton 談 constructor
從 Singleton 談 constructor從 Singleton 談 constructor
從 Singleton 談 constructorLuba Tang
 
Ruby 使用手冊 (Part 1)
Ruby 使用手冊 (Part 1)Ruby 使用手冊 (Part 1)
Ruby 使用手冊 (Part 1)Drake Huang
 
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7Justin Lin
 
JavaScript现代化排错实践
JavaScript现代化排错实践JavaScript现代化排错实践
JavaScript现代化排错实践jeffz
 
Swift 程序语言介绍
Swift 程序语言介绍Swift 程序语言介绍
Swift 程序语言介绍明 李
 
C python 原始碼解析 投影片
C python 原始碼解析 投影片C python 原始碼解析 投影片
C python 原始碼解析 投影片kao kuo-tung
 
为啥别读HotSpot VM的源码(2012-03-03)
为啥别读HotSpot VM的源码(2012-03-03)为啥别读HotSpot VM的源码(2012-03-03)
为啥别读HotSpot VM的源码(2012-03-03)Kris Mok
 
compiler fuzzer : prog fuzz介紹
compiler fuzzer : prog fuzz介紹compiler fuzzer : prog fuzz介紹
compiler fuzzer : prog fuzz介紹fdgkhdkgh tommy
 
並行與平行
並行與平行並行與平行
並行與平行Justin Lin
 
從技術面簡介線上遊戲外掛
從技術面簡介線上遊戲外掛從技術面簡介線上遊戲外掛
從技術面簡介線上遊戲外掛John L Chen
 
COSCUP 2016 - LLVM 由淺入淺
COSCUP 2016 - LLVM 由淺入淺COSCUP 2016 - LLVM 由淺入淺
COSCUP 2016 - LLVM 由淺入淺宗凡 楊
 
千呼萬喚始出來的 Java SE 7
千呼萬喚始出來的 Java SE 7千呼萬喚始出來的 Java SE 7
千呼萬喚始出來的 Java SE 7Justin Lin
 

What's hot (17)

The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)
 
Wind.js无障碍调试与排错
Wind.js无障碍调试与排错Wind.js无障碍调试与排错
Wind.js无障碍调试与排错
 
ajax_onlinemad
ajax_onlinemadajax_onlinemad
ajax_onlinemad
 
Node.js 异步任务的四种模式
Node.js 异步任务的四种模式Node.js 异步任务的四种模式
Node.js 异步任务的四种模式
 
從 Singleton 談 constructor
從 Singleton 談 constructor從 Singleton 談 constructor
從 Singleton 談 constructor
 
Ruby 使用手冊 (Part 1)
Ruby 使用手冊 (Part 1)Ruby 使用手冊 (Part 1)
Ruby 使用手冊 (Part 1)
 
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
 
JavaScript现代化排错实践
JavaScript现代化排错实践JavaScript现代化排错实践
JavaScript现代化排错实践
 
Swift 程序语言介绍
Swift 程序语言介绍Swift 程序语言介绍
Swift 程序语言介绍
 
Nio trick and trap
Nio trick and trapNio trick and trap
Nio trick and trap
 
C python 原始碼解析 投影片
C python 原始碼解析 投影片C python 原始碼解析 投影片
C python 原始碼解析 投影片
 
为啥别读HotSpot VM的源码(2012-03-03)
为啥别读HotSpot VM的源码(2012-03-03)为啥别读HotSpot VM的源码(2012-03-03)
为啥别读HotSpot VM的源码(2012-03-03)
 
compiler fuzzer : prog fuzz介紹
compiler fuzzer : prog fuzz介紹compiler fuzzer : prog fuzz介紹
compiler fuzzer : prog fuzz介紹
 
並行與平行
並行與平行並行與平行
並行與平行
 
從技術面簡介線上遊戲外掛
從技術面簡介線上遊戲外掛從技術面簡介線上遊戲外掛
從技術面簡介線上遊戲外掛
 
COSCUP 2016 - LLVM 由淺入淺
COSCUP 2016 - LLVM 由淺入淺COSCUP 2016 - LLVM 由淺入淺
COSCUP 2016 - LLVM 由淺入淺
 
千呼萬喚始出來的 Java SE 7
千呼萬喚始出來的 Java SE 7千呼萬喚始出來的 Java SE 7
千呼萬喚始出來的 Java SE 7
 

Similar to C++11综述/新特性描述/Overview of C++11 New Features

Go语言: 互联网时代的C
Go语言: 互联网时代的CGo语言: 互联网时代的C
Go语言: 互联网时代的CGoogol Lee
 
模块一-Go语言特性.pdf
模块一-Go语言特性.pdf模块一-Go语言特性.pdf
模块一-Go语言特性.pdfczzz1
 
認識 C++11 新標準及使用 AMP 函式庫作平行運算
認識 C++11 新標準及使用 AMP 函式庫作平行運算認識 C++11 新標準及使用 AMP 函式庫作平行運算
認識 C++11 新標準及使用 AMP 函式庫作平行運算建興 王
 
Node develop expirements
Node develop expirementsNode develop expirements
Node develop expirementsaleafs
 
竞赛中C++语言拾遗
竞赛中C++语言拾遗竞赛中C++语言拾遗
竞赛中C++语言拾遗乐群 陈
 
JavaScript 80+ Programming and Optimization Skills
JavaScript 80+ Programming and Optimization SkillsJavaScript 80+ Programming and Optimization Skills
JavaScript 80+ Programming and Optimization SkillsHo Kim
 
02.python基础
02.python基础02.python基础
02.python基础modou li
 
5, initialization & cleanup
5, initialization & cleanup5, initialization & cleanup
5, initialization & cleanupted-xu
 
Intro to C++ Basic
Intro to C++ BasicIntro to C++ Basic
Intro to C++ BasicShih Chi Lin
 
JCConf 2023 - 深入淺出 Java 21 功能
JCConf 2023 - 深入淺出 Java 21 功能JCConf 2023 - 深入淺出 Java 21 功能
JCConf 2023 - 深入淺出 Java 21 功能Joseph Kuo
 
02 Objective-C
02 Objective-C02 Objective-C
02 Objective-CTom Fan
 
1 C入門教學
1  C入門教學1  C入門教學
1 C入門教學Sita Liu
 
C++11 smart pointers
C++11 smart pointersC++11 smart pointers
C++11 smart pointerschchwy Chang
 
COSCUP2016 - LLVM框架、由淺入淺
COSCUP2016 - LLVM框架、由淺入淺COSCUP2016 - LLVM框架、由淺入淺
COSCUP2016 - LLVM框架、由淺入淺hydai
 
12, string
12, string12, string
12, stringted-xu
 
twMVC#43 C#10 新功能介紹
twMVC#43 C#10 新功能介紹twMVC#43 C#10 新功能介紹
twMVC#43 C#10 新功能介紹twMVC
 
Ecmascript
EcmascriptEcmascript
Ecmascriptjay li
 
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫Justin Lin
 
COSCUP 2014 : open source compiler 戰國時代的軍備競賽
COSCUP 2014 : open source compiler 戰國時代的軍備競賽COSCUP 2014 : open source compiler 戰國時代的軍備競賽
COSCUP 2014 : open source compiler 戰國時代的軍備競賽Kito Cheng
 

Similar to C++11综述/新特性描述/Overview of C++11 New Features (20)

Go语言: 互联网时代的C
Go语言: 互联网时代的CGo语言: 互联网时代的C
Go语言: 互联网时代的C
 
模块一-Go语言特性.pdf
模块一-Go语言特性.pdf模块一-Go语言特性.pdf
模块一-Go语言特性.pdf
 
認識 C++11 新標準及使用 AMP 函式庫作平行運算
認識 C++11 新標準及使用 AMP 函式庫作平行運算認識 C++11 新標準及使用 AMP 函式庫作平行運算
認識 C++11 新標準及使用 AMP 函式庫作平行運算
 
Node develop expirements
Node develop expirementsNode develop expirements
Node develop expirements
 
竞赛中C++语言拾遗
竞赛中C++语言拾遗竞赛中C++语言拾遗
竞赛中C++语言拾遗
 
JavaScript 80+ Programming and Optimization Skills
JavaScript 80+ Programming and Optimization SkillsJavaScript 80+ Programming and Optimization Skills
JavaScript 80+ Programming and Optimization Skills
 
02.python基础
02.python基础02.python基础
02.python基础
 
5, initialization & cleanup
5, initialization & cleanup5, initialization & cleanup
5, initialization & cleanup
 
Intro to C++ Basic
Intro to C++ BasicIntro to C++ Basic
Intro to C++ Basic
 
JCConf 2023 - 深入淺出 Java 21 功能
JCConf 2023 - 深入淺出 Java 21 功能JCConf 2023 - 深入淺出 Java 21 功能
JCConf 2023 - 深入淺出 Java 21 功能
 
Tcfsh bootcamp day2
 Tcfsh bootcamp day2 Tcfsh bootcamp day2
Tcfsh bootcamp day2
 
02 Objective-C
02 Objective-C02 Objective-C
02 Objective-C
 
1 C入門教學
1  C入門教學1  C入門教學
1 C入門教學
 
C++11 smart pointers
C++11 smart pointersC++11 smart pointers
C++11 smart pointers
 
COSCUP2016 - LLVM框架、由淺入淺
COSCUP2016 - LLVM框架、由淺入淺COSCUP2016 - LLVM框架、由淺入淺
COSCUP2016 - LLVM框架、由淺入淺
 
12, string
12, string12, string
12, string
 
twMVC#43 C#10 新功能介紹
twMVC#43 C#10 新功能介紹twMVC#43 C#10 新功能介紹
twMVC#43 C#10 新功能介紹
 
Ecmascript
EcmascriptEcmascript
Ecmascript
 
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫
 
COSCUP 2014 : open source compiler 戰國時代的軍備競賽
COSCUP 2014 : open source compiler 戰國時代的軍備競賽COSCUP 2014 : open source compiler 戰國時代的軍備競賽
COSCUP 2014 : open source compiler 戰國時代的軍備競賽
 

C++11综述/新特性描述/Overview of C++11 New Features

  • 2. Agenda • 基本特性 – auto, loop, raw string, unicode, nullptr, initialization, default/delete, static_assert, constexpr, lambda, variadic template, move, ... • 多线程 – thread, async, future, promise, atomics, mutex, lock, condition var, thread_local, ... • 标准库 – shared_ptr, unique_ptr, unordered_map/set, tuple, regex, function, bind, time, ...
  • 4. auto, decltype • auto: 类型声明 – auto i = 10; – auto iter = vec.begin(); – 可以和const, pointer, reference, volatile一起使用 • auto& n = i; • auto* pi = &i; • const auto d = i; • decltype: 变量推断类型 – int i; decltype(i) i2 = i; // 等同于 auto i2 = i; – 主要用在template里, 方便书写 • template<typename T, typename S> • auto multiply(T lhs, S rhs) -> decltype(lhs * rhs) { return lhs * rhs; }
  • 5. Loop:range-based • 用于所有的stl标准容器 • 数组, 初始化列表 • UDT: 要求begin(), end()提供有效的遍历 • for (const auto& e : vec) { //const&避免copy • cout << e << “n”; • }
  • 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';
  • 7. nullptr • 表示一个空指针 – int* p = nullptr; – if (p == NULL) { ... } // still works • 类型安全: nullptr是一个指针, 不是其他 – void f(char const *ptr); – void f(int v); – f(NULL); // calls f(int v) – f(nullptr); // calls f(char const* ptr)
  • 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函数应当同样不抛出异常
  • 15. delete/default • delete: 申明的函数不可被调用 – 举例:基类中阻止copy constructor:防止slicing • class B { // GOOD: base class suppresses copying • B(const B&) = delete; • B& operator=(const B&) = delete; • virtual unique_ptr<B> clone() { return /* B object */; } • // ... • }; • default: 使用编译器默认产生的函数 • class Tracer { • string message; • public: • Tracer(const string& m) : message{m} { cerr << "entering " << message << 'n'; } • ~Tracer() { cerr << "exiting " << message << 'n'; } • Tracer(const Tracer&) = default; • Tracer& operator=(const Tracer&) = default; • Tracer(Tracer&&) = default; • Tracer& operator=(Tracer&&) = default; • };
  • 16. override/final • 虚函数, 在申明的时候使用virtual/override/final三者之一: – virtual: 当申明一个新的虚函数 – override: 当需要复写一个虚函数 – final: 不可再被复写 • struct B { • void f1(int); • virtual void f2(int) const; • virtual void f3(int); • // ... • }; • struct D : B { • void f1(int); // warn: D::f1() hides B::f1() • void f2(int) const; // warn: no explicit override • void f3(double); // warn: D::f3() hides B::f3() • // ... • }; • struct D2 : B { • virtual void f2(int) final; // BAD; pitfall, D2::f2 does not override B::f2 • };
  • 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!
  • 21. move • move constructor/assigment – 增加效率,copy代价可能太高 – 我们有时候并不需要copy, 比如我们只想保留使用其中一个,例如其中一个是临时的对象 – class_name ( class_name && ) – class_name & operator=(class_name && other) – 一个例子: • IoBuf(IoBuf&& other) { • _data = other._data; • _length = other._length; • other._data = nullptr;// 让other这个临时对象无效 • other._length = 0; // 不然othter的destructor会delete _data! • } • IoBuf& operator=(IoBuf&& other) { • if (this != &other) { • delete[] _data; • _data = other._data; • _length = other._length; • other._data = nullptr;// 让other这个临时对象无效 • other._length = 0; // 不然othter的destructor会delete _data! • } • }
  • 22. Variadic template • 可变参数模板 – 模板参数的个数可变的情形 – template <typename... T> – 通常和递归模板结合 – 举例:printf – 举例:QA想测试函数的时间开销,但不同函 数的参数都不相同 – 举例:遍历数组
  • 26. 多线程 • c++11之前 – Boost thread (和c++11 thread差不多) – libpthread, openmp, mpi – 公司内部各种线程库 • C++11 – Thread: 独立的可执行单元 – Mutex: 共享数据的访问控制 – conditional_variable: block-until-true execution – future, async: 异步调用 – Atomic: 原子性访问操作
  • 27. pthread vs std::thread • pthread是C函数库 – 设计没有覆盖有关C++的问题 • 对象生命周期 • Exception – pthread_cancel没有类似的c++功能 • std::thread – 作为线程执行的抽象 – 提供了一组其他类来管理线程执行中的问题 • Mutex • Conditional_variable • Lock – 提供了丰富的创建可调用对象(callable)的函数,如lamda – RAII作为设计的核心思想,管理线程资源(lock, mutex)
  • 28. std::thread • 接受任何可调用的对象, 异步方式运行 – std::thread(func, arg1, arg2, ..., argN); – func: 可以lamda, functor, 函数指针 – E.g.: std::thread t([]{std::cout << “hello world.n”}); – 主要方法 • Join() – main退出的时候,所有运行中的线程都应先join(),不然退出会造成undefined behavior – 如果一个thread变量在销毁前没有join()/detach(),也会造成可能的crash • Detach() • Get_id() • std:thread::get_hardware_concurrency() – 数据共享问题避免 • Pass by value (多个线程使用同一份数据,考虑copy) • 保证共享的数据其生命周期比线程更久 – 异常 • 永远不要把异常抛出std::thread外,这样会导致undefined behavior • 线程安全:在线程内接住处理所有异常
  • 30. async, future • std::async – 用来构造std::future的一个函数模版,用来异步执 行一个函数,支持两种launch policy: – std::launch::async • 产生一个新的线程来运行 – std::launch::deferred • 在当前线程中运行 – 适合debug – 在future.get()的时候运行 • std::future – 用来表示async返回结果的一个类 – 允许异常或者value作为返回结果
  • 31. async, future • 如何获得执行结果 – future.get() • 等待直到函数执行结束返回 • 返回值通过move/copy取得 • 可以是std::future<void>,如果没有返回值 – 除了get(),还有wait() • 等待执行结束 • 可以指定等待timeout(比如万一函数执行过长怎么办)
  • 32. promise, packaged_task • std::packaged_task – async提供了高level的异步调用, packaged_task和promise相当于低level的实 现 – packaged_task是一个可调用对象(类似std::function) • void operator() – promise.set_value(fn(std::forward<Ts>(ts)...)); // fulfill the promise – 提供了获得调用结果的接口 • std::future<std::string> get_future() • std::promise<T> – future的provider – 相当于连接future和packaged_task – asnync的工作相当于: • promise<int> intPromise; // 创建promise • future<int> intFuture = intPromise.get_future(); • std::thread t(asyncFunc, std::move(intPromise)); // or packaged_task • result = intFuture.get(); // may throw MyException
  • 33. mutex • 多种类型 – std::mutex – std::timed_mutex – std::recursive_mutex; – std::recursive_timed_mutex • recursive_mutex – 同一个线程内可以反复lock: 多次lock不会死锁 • Recursive mutex ownership属于上锁的线程, 只有这个线程才能 unlock, 其他线程不可以(不同于mutex, 可以由另一个线程 unlock) – 其他线程则会在lock时等待 – 一个线程lock了n次, 必须unlock n次才能解锁
  • 34. mutex • Recursive mutex – void foo() – { – ... mutex_acquire(); – ... foo(); // 递归调用, 不用recursive mutex会死锁 – ... mutex_release(); – } • 通常情况下, 应避免使用recursive_mutex, 考虑 其他设计
  • 35. mutex • Lock (block) – 对mutex上锁, 如果mutex已被lock, 那么阻塞在那里(non recursive mutex) • Unlock – 对mutex解锁 • Try_lock (fail) – 试图mutex加锁, 如果无法上锁, 则返回false(和lock的区别在 于try_lock始终是非阻塞的) • Try_lock_for (timed_mutex) – 试图在给定的时间(std::chrono::duration)内加锁, 如果不成功 则在duration后返回false, 否则在加锁时刻返回true • Try_lock_until (timed_mutex) – Std::chrono::time_point
  • 36. mutex • timed_mutex – 当某个线程必须每隔一定时间做一件事情的时候 – 当某个线程在给定的时间内必须完成一件事情的时 候 void recover_task() { // acquire imtx.lock std::future<bool> result = std::async(recover_from_disk()); if (imtx.try_lock_for(std::chrono::milliseconds(1000)) { std::cout << "recover done.n"; } else { std::cout << "oops, recovery not finisned in 1s, check recover status.n"; } }
  • 37. lock • RAII wrapper of mutex – 在构造函数里对mutex上锁,析构的时候解锁 – std::lock_guard vs. std::unique_lock • unique_lock提供了unlock()方法 • lock_guard没有unlock()可供调用,在析构的时候自动释 放 • std::lock – 对多个lockable object上锁 • std::unique_lock<std::mutex> l1(m1, std::defer_lock); std::unique_lock<std::mutex> l2(m2, std::defer_lock); std::lock(l1, l2);
  • 38. conditional_variable • 提供了一种多线程间同步的机制 – 用来阻塞一个或多个线程的执行, 直到另一个线程改变一个共享的变量条 件并通知阻塞等待的线程 – 可以用来作为事件通知机制 – 通常需要: • conditional_variable • mutex • shared variable (boolean) – 线程1: • 获得mutex • 修改共享的条件变量 • 通知等待线程 (notify(), notify_all()) – 线程2: • 获得mutex • 等待(wait()), 阻塞执行 • wait() = while(!pred()) { wait(lock); } • 等待结束的时候mutex自动获得, 检查共享的条件变量, 决定干活还是继续等 • Lost notification = dead lock!
  • 42. 智能指针 • Shared_ptr – 引用计数实现 – 当引用计数减到0的时候, 自动销毁对象 – E.g.: • std::shared_ptr<int> p(new int); // alloc int + mgr obj • auto p = std::make_shared<int>(); // prefer, 少一次内存分配 • Unique_ptr – 管理动态产生的内存对象, 提供显式的ownership语义, 推荐使用让代码更卫生 • Weak_ptr
  • 44. 智能指针 • 当对象分配产生, 并有第一个shared_ptr指向它的时候 – shared_ptr的构造函数生成一个manager object, manager object存放ref count(shared count和weak count), 并且有真正 指向对象的指针 – shared count纪录多少个shared_ptr指向那个manager object, weak count纪录多少个weak_ptr指向那个manager object – 一开始, shared_count = 1, weak count = 0 – 当新的shared_ptr/weak_ptr指向此manager object时候, ++count – 当shared_ptr销毁或者指向其他的时候, --shared count – 当shared count减到0的时候, delete那个managed object(注意 不是manager object) • 如果此时weak count = 0, 那么删除manager object • 如果此时weak count > 0, 那么保留manager object
  • 45. 容器 • array:内存连续 – Fixed size(vs. vector), random access – E.g.:array<int,6> a = { 1, 2, 3 }; • forward_list: singly linked list – 内存开销少 – 没有size() • unordered_map/multimap: – 基于hash, 查询/插入/删除O(1) • unordered_set/multiset
  • 46. tuple • 保存不同类型的对象 – 类似std::pair, 不过可以有任意个 • tuple<string,int,double,int> info(“string",2,3.14,82); • get(X)获得tuple中第X个对象, auto s = get<0> info; • 或者用tie: tie(s,a,b,c) = info; – 用途 • 返回多个对象 – std::tuple<int, std::string> func(); – tie(err_code, err_msg) = func(); • 方便利用模板(和variadic template配合)
  • 47. regex • <regex> – 构造regular expression, 语法支持多种选项 • ECMAScript: (preferred) – http://www.cplusplus.com/reference/regex/ECMAScript/ • basic: – POSIX • extended – extended POSIX • awk, grep, egrep, ... – http://en.cppreference.com/w/cpp/regex/syntax_option_type • 构造一个regex可能是耗时的,如果expression不变反复使用,那么最好作为一个静态的变量构造 一次 – match: • std::regex_match: 是否字符串完全匹配pattern – search: • Find one: – std::regex_search:是否含有子串匹配pattern • Find all: – std::cregex_iterator, std::sregex_iterator, std::wcregex_iterator, std::wsregex_iterator – replace: • std::regex_replace:返回一份字符串的copy, 替换其中所有匹配的字串
  • 49. function • store/copy/invoke – function, 函数指针 – lamda表达式 – bind表达式 – functor • 比函数指针强大 – 能捕获local变量 – 能调用类函数 (capture *this) • void (*callbackFunc)(int); • std::function< void(int) > callbackFunc; //preferred
  • 50. chrono • Time point – 以距离epoch的duration表示 • Duration:时间间隔 – 一些预定义的时间间隔包括 • std::chrono::nanoseconds • std::chrono::microseconds • std::chrono::milliseconds • std::chrono::seconds • std::chrono::minutes • std::chrono::hours • Clock – 三种类型,按照ISO • system_clock:system wall clock,例如可能随DST改变 • steady_clock:time point随着物理时间以相同的速度增加,不会减少 • high_resolution_clock:系统提供的最小tick的时钟 – 实际上,gcc实现三者没有区别 • typedef system_clock steady_clock; • typedef system_clock high_resolution_clock;
  • 51. chrono • 例子 – std::chrono::duration<int,std::ratio<60*60*24> > one_day (1);//1天=60*60*24秒 – – system_clock::time_point today = system_clock::now(); – system_clock::time_point tomorrow = today + one_day; – typedef std::chrono::high_resolution_clock clock; – typedef std::chrono::milliseconds milliseconds; – – clock::time_point t0 = clock::now(); – // ... some operation to time estimate – clock::time_point t1 = clock::now(); – – milliseconds total_ms = std::chrono::duration_cast<milliseconds>(t1 - t0);