C++11的一些新特性

一、

1. std::move()

std::move 用于指示对象 t 可以“被移动”,即允许从 t 到另一对象的有效率的资源传递。

特别是, std::move 生成标识其参数 t 的亡值表达式。它准确地等价于到右值引用类型的 static_cast 。

注解

以右值参数(如临时对象的纯右值或如 std::move 所产生者的亡值之一)调用函数时,重载决议选择接受右值引用参数的版本(包含移动构造函数、移动赋值运算符及常规成员函数,如 std::vector::push_back )。若参数标识一个占有资源的对象,则这些重载拥有移动参数所保有的任何资源的选择,但不强求如此。例如,链表的移动构造函数可以复制指向表头的指针,并将 nullptr 存储到参数中,而非分配并复制逐个结点。

右值引用变量的名称是左值,而若要绑定到接受右值引用参数的重载,就必须转换到亡值,此乃移动构造函数与移动赋值运算符典型地使用 std::move 的原因:

// 简单的移动构造函数
A(A&& arg) : member(std::move(arg.member)) // 表达式 "arg.member" 为左值
{} 
// 简单的移动赋值运算符
A& operator=(A&& other) {
     member = std::move(other.member);
     return *this;
}

一个例外是当函数参数类型是到模板形参的右值引用(“转发引用”或“通用引用”)时,该情况下转而使用 std::forward 。

除非另外指定,否则所有已被移动的标准库对象被置于合法但未指定的状态。即只有无前提的函数,例如赋值运算符,才能安全地在对象被移动后使用:

std::vector<std::string> v;
std::string str = "example";
v.push_back(std::move(str)); // str 现在合法但未指定
str.back(); // 若 size() == 0 则为未定义行为: back() 拥有前提 !empty()
str.clear(); // OK , clear() 无前提

而且,以亡值参数调用的标准库函数可以假设该参数是到对象的唯一引用;若它从左值带 std::move 构造,则不进行别名检查。然而标准库类型的自移动赋值保证将对象置于合法(但未指定的)状态:

std::vector<int> v = {2, 3, 3};
v = std::move(v); // v 的值未指定

2. std::forward()

 1)转发左值为左值或右值,依赖于 T

当 t 是转发引用(作为到无 cv 限定函数模板形参的右值引用的函数实参),此重载将参数以在传递给调用方函数时的值类别转发给另一个函数。

例如,若用于如下的包装器,则模板表现为下方所描述:

template<class T>
void wrapper(T&& arg) 
{
    // arg 始终是左值
    foo(std::forward<T>(arg)); // 转发为左值或右值,依赖于 T
}
  • 若对 wrapper() 的调用传递右值 std::string ,则推导 T 为 std::string (非 std::string& 或 std::string&& ,且 std::forward 确保将右值引用传递给 foo 。
  • 若对 wrapper() 的调用传递 const 左值 std::string ,则推导 T 为 const std::string& ,且 std::forward 确保将 const 左值引用传递给 foo 。
  • 若对 wrapper() 的调用传递非 const 左值 std::string ,则推导 T 为 std::string& ,且 std::forward 确保将非 const 左值引用传递给 foo 。

2)转发右值为右值并禁止右值的转发为左值

此重载令转发表达式(如函数调用)的结果可行,结果可以是右值或左值,同转发引用参数的原始值类别。

3. std::function

类模板 std::function 是通用多态函数包装器。 std::function 的实例能存储、复制及调用任何可复制构造 (CopyConstructible) 的可调用 (Callable) 目标——函数、 lambda 表达式、 bind 表达式或其他函数对象,还有指向成员函数指针和指向数据成员指针。

存储的可调用对象被称为 std::function 的目标。若 std::function 不含目标,则称它为空。调用空 std::function 的目标导致抛出 std::bad_function_call 异常。

std::function 满足可复制构造 (CopyConstructible) 和可复制赋值 (CopyAssignable)

注解

当结果类型为引用的 std::function 从无尾随返回类型的 lambda 表达式初始化时需要留心。由于 auto 推导的起效方式,这种 lambda 表达式将始终返回纯右值。故而结果引用将始终绑定到生命期在 std::function::operator() 返回时结束的临时量。

std::function<const int&()> F([]{ return 42; });
int x = F(); // 未定义行为: F() 的结果是悬垂引用

4. std::bind

函数模板 bind 生成 f 的转发调用包装器。调用此包装器等价于以一些绑定到 args 的参数调用 f 。

参数

 f - 可调用 (Callable) 对象(函数对象、指向函数指针、到函数引用、指向成员函数指针或指向数据成员指针)

args - 要绑定的参数列表,未绑定参数为命名空间 std::placeholders 的占位符 _1, _2, _3... 所替换

注解

如可调用 (Callable) 中描述,调用指向非静态成员函数指针或指向非静态数据成员指针时,首参数必须是引用或指针(可以包含智能指针,如 std::shared_ptr 与 std::unique_ptr),指向将访问其成员的对象。

到 bind 的参数被复制或移动,而且决不按引用传递,除非包装于 std::ref 或 std::cref 。

允许同一 bind 表达式中的多重占位符(例如多个 _1 ),但结果仅若对应参数( u1 )是左值或不可移动右值才良好定义。

 5. 可变模板参数

见https://www.cnblogs.com/Glucklichste/p/11175769.html

 

二、线程支持库

1. <thread>

1.1 类thread

类 thread 表示单个执行线程。线程允许多个函数同时执行。

获取线程id

获取线程id有两种方法:

  1. 通过thread的实例调用get_id()直接获取
  2. 在当前线程上调用std::this_thread::get_id()获取

线程合并和分离

  • join()
  • detach()
  • joinable()

在线程创建后,需要在线程销毁前决定线程以何种方式结束,调用join()或detach()。同时,在线程结束前我们可以调用joinable()判断线程以何种方式结束。

线程随眠

std::this_thread::sleep_for(std::chrono::seconds(3)); //休眠三秒
std::this_thread::sleep_for(std::chrono::milliseconds(100)); //休眠一百毫秒

2. <mutex>

2.1 类mutex

mutex 类是能用于保护共享数据免受从多个线程同时访问的同步原语。

  • 调用方线程从它成功调用 locktry_lock 开始,到它调用 unlock 为止占有 mutex 。
  • 线程占有 mutex 时,所有其他线程若试图要求 mutex 的所有权,则将阻塞(对于 lock 的调用)或收到 false 返回值(对于 try_lock ).
  • 调用方线程在调用 lock 或 try_lock 前必须不占有 mutex 。

除此之外,还有一个带定时功能的锁,timed_mutex。

还有能够被同一线程递归锁定的互斥设备,recursive_mutex,recursive_timed_mutex,但不建议使用。

2.2 std::lock_guard

类 lock_guard 是互斥体包装器,为在作用域块期间占有互斥提供便利 RAII 风格机制。

创建 lock_guard 对象时,它试图接收给定互斥的所有权。控制离开创建 lock_guard 对象的作用域时,销毁 lock_guard 并释放互斥。

lock_guard 不提供加解锁的成员方法。

2.3 unique_lock

类 unique_lock 是通用互斥包装器,允许延迟锁定、锁定的有时限尝试、递归锁定、所有权转移和与条件变量一同使用。

unique_lock可以看作是lock_guard的升级版。

unique_lock提供了加解锁的成员方法,同时,可以在构造时添加第二个参数来实现构造时不加锁。

2.4 call_once()

 

 准确执行一次可调用 (Callable) 对象 f ,即使同时从多个线程调用。

类std::noce_flag

此类是call_once()方法的辅助类。

3. <condition_variable>

3.1 condition_variable

condition_variable 类是同步原语,能用于阻塞一个线程,或同时阻塞多个线程,直至另一线程修改共享变量(条件)并通知 condition_variable 。

任何有意在 std::condition_variable 上等待的线程必须:

  1. 在与用于保护共享变量者相同的互斥上获得 std::unique_lock<std::mutex>
  2. 执行下列行为:
    1. 检查条件,是否为已更新或提醒它的情况
    2. 执行wait、 wait_for 或  ,等待操作自动释放互斥,并悬挂线程的执行。
    3. condition_variable 被通知时,时限消失或虚假唤醒发生,线程被唤醒,且自动重获得互斥。之后线程应检查条件,若唤醒是虚假的,则继续等待。

      或者

    1. 使用 wait 、 wait_for 及 wait_until 的有谓词重载,它们包揽以上三个步骤。它们都要提供谓词作为检查条件。        

condition_variable必须与unique_lock配合使用。

通知

notify_one()和notify_all()。

3.2 condition_variable_any

condition_variable_any 类是 std::condition_variable 的泛化。相对于只在 std::unique_lock<std::mutex> 上工作的 std::condition_variable , condition_variable_any 能在任何满足基本可锁定 (BasicLockable) 要求的锁上工作。

4. <future>

 4.1 类模板future

类模板 std::future 提供访问异步操作结果的机制:

  • (通过 std::async 、 std::packaged_task 或 std::promise 创建的)异步操作能提供一个 std::future 对象给该异步操作的创建者。
  • 然后,异步操作的创建者能用各种方法查询、等待或从 std::future 提取值。若异步操作仍未提供值,则这些方法可能阻塞。
  • 异步操作准备好发送结果给创建者时,它能通过修改链接到创建者的 std::future 的共享状态(例如 std::promise::set_value )进行。

future对象支持移动,但不可复制。

获取结果

future可以使用成员函数get()返回结果,如果异步操作未提供值,该方法会阻塞等待。future的结果只能访问一次。

4.2 函数模板async()

函数模板 async 异步地运行函数 f (潜在地在可能是线程池一部分的分离线程中),并返回最终将保有该函数调用结果的 std::future 。

async()还可以调用重载版本,可以自行设置调用策略std::launch::async(启用异步求值)、

std::launch::deferred (启用惰性求值)。

4.3 类模板packaged_task

类模板 std::packaged_task 包装任何可调用 (Callable) 目标(函数、 lambda 表达式、 bind 表达式或其他函数对象),使得能异步调用它。其返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。

正如 std::function , std::packaged_task 是多态、具分配器的容器:可在堆上或以提供的分配器分配存储的可调用对象。

packaged_task的使用行为模式和普通函数一样。

获取结果

packaged_task可以使用成员函数get_future()返回与承诺的结果关联的 std::future。

4.4 类模板promise

类模板 std::promise 提供存储值或异常的设施,之后通过 std::promise 对象所创建的 std::future 对象异步获得结果。注意 std::promise 只应当使用一次。

promise主要用于线程间通信。

获取结果

promise可以使用成员函数get_future()返回与承诺的结果关联的 std::future。

设置结果

promise可以使用成员函数set_value()来设置结果为指定值,并通知相关联的future对象。

三、原子库

1. <atomic>

1.1 类模板atomic

 

 

 

 

-----------------------------------------------------------------------------------------------------------------

 https://zh.cppreference.com/

posted @ 2022-03-06 15:46  幻cat  阅读(152)  评论(0编辑  收藏  举报