Item 40: 当需要并发时使用std::atomic,特定内存才使用volatile 可伶的volatile。如此令人迷惑。本不应该出现在本章节,因为它没有关于并发的能力。但是在其他编程语言中(比如,Java和C#),volatile是有并发含义的,即使在C++中,有些编译器在实现时也将并发的某种含义加入到了volatile关键字中。因此在此值得讨论下关于volatile关键字的含义以消除异议
有时,一个任务通知另一个异步执行的任务发生了特定的事件很有用,因为第二个任务要等到特定事件发生之后才能继续执行。事件也许是数据已经初始化,也许是计算阶段已经完成,或者检测到重要的传感器值。这种情况,什么是线程间通信的最佳方案? 一个明显的方案就是使用条件变量(condvar)。如果我们将检测条件的任务称为检测任务,对条件作出反应的任务称为反应任务,策略很简单:反应任务等待一个条件变量,检测任务在事
Item 37中说明了joinable的std::thread对应于可执行的系统线程。non-defered任务的future(参见Item 36)与系统线程有相似的关系。因此,可以将std::thread对象和future对象都视作系统线程的句柄。 从这个角度来说,有趣的是std::thread和futures在析构时有相当不同的行为。在Item 37中说明,joinable的std::thre
每个std::thread对象处于两个状态之一:joinable or unjoinable。joinable状态的std::thread对应于正在运行或者可能正在运行的异步执行线程。比如,一个blocked或者等待调度的std::thread是joinable,已运行结束的std::thread也可以认为是joinable unjoinable的std::thread对象比如: Default-
当你调用std::async执行函数时(或者其他可调用对象),你通常希望异步执行函数。但是这并不一定是你想要std::async执行的操作。你确实通过std::asynclaunch policy(译者注:这里没有翻译)要求执行函数,有两种标准policy,都通过std::launch域的枚举类型表示(参见Item10关于枚举的更多细节)。假定一个函数f传给std::async来执行: std::
C++11的伟大标志之一是将并发整合到语言和库中。熟悉其他线程API(比如pthreads或者Windows threads)的开发者有时可能会对C++提供的斯巴达式(译者注:应该是简陋和严谨的意思)功能集感到惊讶,这是因为C++对于并发的大量支持是在编译器的约束层面。由此产生的语言保证意味着在C++的历史中,开发者首次通过标准库可以写出跨平台的多线程程序。这位构建表达库奠定了坚实的基础,并发标准
C++11中的std::bind是C++98的std::bind1st和std::bind2nd的后续,但在2005年已经成为了标准库的一部分。那时标准化委员采用了TR1的文档,其中包含了bind的规范。(在TR1中,bind位于不同的命名空间,因此它是std::tr1::bind,而不是std::bind,接口细节也有所不同)。这段历史意味着一些程序员有十年或更长时间的使用std::bind经验
泛型lambda(generic lambdas)是C++14中最值得期待的特性之一——因为在lambda的参数中可以使用auto关键字。这个特性的实现是非常直截了当的:即在闭包类中的operator()函数是一个函数模版。例如存在这么一个lambda: auto f = [](auto x){ return func(normalize(x)); }; 对应的闭包类中的函数调用操作符看来就变
在某些场景下,按值捕获和按引用捕获都不是你所想要的。如果你有一个只能被移动的对象(例如std::unique_ptr或std::future)要进入到闭包里,使用C++11是无法实现的。如果你要复制的对象复制开销非常高,但移动的成本却不高(例如标准库中的大多数容器),并且你希望的是宁愿移动该对象到闭包而不是复制它。然而C++11却无法实现这一目标。 但如果你的编译器支持C++14,那又是另一回事了
Lambda表达式是C++编程中的游戏规则改变者。这有点令人惊讶,因为它没有给语言带来新的表达能力。Lambda可以做的所有事情都可以通过其他方式完成。但是lambda是创建函数对象相当便捷的一种方法,对于日常的C++开发影响是巨大的。没有lambda时,标准库中的_if算法(比如,std::find_if, std::remove_if, std::count_if等)通常需要繁琐的谓词,但是当
C++11最显眼的功能之一就是完美转发功能。完美转发,太棒了!哎,开始使用,你就发现“完美”,理想与现实还是有差距。C++11的完美转发是非常好用,但是只有当你愿意忽略一些失败情况,这个Item就是使你熟悉这些情形。 在我们开始epsilon探索之前,有必要回顾一下“完美转发”的含义。“转发”仅表示将一个函数的参数传递给另一个函数。对于被传递的第二个函数目标是收到与第一个函数完全相同的对象。这就排
移动语义可以说是C++11最主要的特性。你可能会见过这些类似的描述“移动容器和拷贝指针一样开销小”, “拷贝临时对象现在如此高效,编码避免这种情况简直就是过早优化”这种情绪很容易理解。移动语义确实是这样重要的特性。它不仅允许编译器使用开销小的移动操作代替大开销的复制操作,而且默认这么做。以C++98的代码为基础,使用C++11重新编译你的代码,然后,哇,你的软件运行的更快了。 移动语义确实令人振奋
Item23中指出,当参数传递给模板函数时,模板参数的类型是左值还是右值被推导出来。但是并没有提到只有当参数被声明为通用引用时,上述推导才会发生,但是有充分的理由忽略这一点:因为通用引用是Item24中才提到。回过头来看,通用引用和左值/右值编码意味着: template<typename T> void func(T&& param); 被推导的模板参数T将根据被传入参数类型被编码为左值或
Item 26中说明了对使用通用引用参数的函数,无论是独立函数还是成员函数(尤其是构造函数),进行重载都会导致一系列问题。但是也提供了一些示例,如果能够按照我们期望的方式运行,重载可能也是有用的。这个Item探讨了几种通过避免在通用引用上重载的设计或者通过限制通用引用可以匹配的参数类型的方式来实现所需行为的方案。 讨论基于Item 26中的示例,如果你还没有阅读Item 26,请先阅读在继续本It
假定你需要写一个函数,它使用name这样一个参数,打印当前日期和具体时间到日志中,然后将name加入到一个全局数据结构中。你可能写出来这样的代码: std::multiset<std::string> names; // global data structure void logAndAdd(const std::string& name) { auto now = std::chro