当你读我们的 发行说明 您会注意到我们添加了大量C++语言特性。这些特征的细节是什么 是 可以在网上找到,但是什么 目的 他们的服务可能仍然模糊不清。本文将试图解释这些新的语言机制的起源以及如何使用它们来获得最佳效果。
基于范围的For循环
【注:2014年12月11日下午1:00太平洋标准时间:2014年6月,Evolution和核心工作组批准了该功能,并在VS 2015 Preview和Clang 3.5中实施,但标准化委员会于11月7日拒绝了该功能,因此该功能将从VS 2015 RTM中删除。新的语法将在2015年5月的下一次委员会会议上提出。]
这个提议 C++ 17的特性允许你省略循环中基于元素的类型:
标准: 矢量 < 内景 >v={1,2,3}; 对于 (一:五) { 打印F( “%%d” ,i); }
你应该记住,这不仅仅是一个语法上的便利。
许多开发者会倾向于写作 汽车 作为元素类型,在大多数情况下,这将正常工作,除了 汽车 它本身会导致元素被复制,这通常是不需要的。此外,元素的突变不会反映在容器中。
一些开发人员可能会试图通过编写 自动& 作为元素类型。这在更多的情况下确实有效,但在某些情况下,它也会破坏:
标准: 矢量 < 布尔 >v={ 是的 , 假 }; 对于 ( 汽车 &一:五) //C4239型 { 打印F( “%%d” , ( 布尔 )i) ; }
这个 标准::向量
警告C4239:使用了非标准扩展:“正在初始化”:从“std::u Vbu reference
如果该扩展被禁用,则此代码将导致编译错误。
由于这些原因,基于简洁范围的For循环的行为与您编写的相同 自动&& 作为元素的类型。这确保了在这种修改有意义的情况下修改容器的元素将正常工作,并且代理类型也得到了正确的处理。
广义Lambda捕获
为了理解引入此特性(也称为“init capture”)的原因,假设您希望生成一些堆分配的数据,以便稍后使用lambda函数进行操作:
汽车 f级( 内景 我 ) { 标准: 唯一u ptr < 内景 >p=标准::使u唯一< 内景 >( 我 ); 返回 [=]( 内景 j ){ 返回 *第+ j ; }; //C2280型 } 内景 主() { 汽车 g=f(42); 打印F( “%%dn” ,g(2)); 打印F( “%%dn” ,g(12)); 返回 0; }
不幸的是,这行不通。编译器将发出:
错误C2280:’std::unique u ptr
因为uniqueu ptr是只移动的类型,所以不允许通过值从封闭范围中捕获它,因为它需要一个副本。
您可以尝试通过引用捕获而不是替换 f 使用:
返回 [&]( 内景 j ){ 返回 * 第+ j ; };
但是 p 一旦超出范围 f 退出,因此当程序运行时,输出是杂乱无章的,反映了当时堆栈上的垃圾:
1160179346 681009
要真正解决这个问题,您需要一种按值捕获仅移动类型的实例的方法。为此,可以使用广义lambda capture替换 f 使用:
返回 [ q=标准::移动(p) ]( 内景 j ){ 返回 *问+ j ; };
斜体代码 移动 价值 p 进入之内 q ,它直接存储在lambda函数本身中,因此直到lambda本身超出范围(在本例中,在 主要的 ). 程序现在按预期运行并打印:
44 54
哲学家用餐
“用餐哲学家问题”是一个常见的场景,用于说明并发资源分配中的死锁。有关更多详细信息,请阅读 这 维基百科上的文章或在互联网或教科书上发现的许多其他描述之一。
初步实施
这将使用资源层次结构解决方案来避免死锁。
#包括 < cstdio公司 > #包括 <线程> #包括 < 互斥 > #包括 <矢量> 班 叉子 { 私有的 : 常数 内景 职位; 标准 :: 互斥 米; 公众的 : 叉子( 内景 位置 ):位置( 位置 ) {} 布尔 皮卡( 内景 位置 ) { 如果 ( m、 尝试锁定 ()) { 打印F ( “哲学家%%d拿起叉子%%d.n” , 位置 , 这 ->职位); 返回 是的 ; } 返回 假 ; } 无效 放下( 内景 位置 ) { m、 解锁 ( ); 打印F ( “哲学家%%d丢了叉子%%d.n” , 位置 , 这 ->职位); } }; 班 哲学家 { 私有的 : 常数 内景 职位; 常数 标准 :: 矢量 < 叉子 *>*叉子; 公众的 : 哲学家( 内景 位置 , 标准 :: 矢量 < 叉子 *> * 叉子 ):位置( 位置 ),叉子( 叉子 ) {} 无效 思考(){ 打印F ( “哲学家%%d正在思考。n” ,位置)_睡眠(10);} 无效 吃(){ 打印F ( “哲学家%%d正在吃东西。n” ,位置)_睡眠(10);} 无效 开始(){ //假设叉子的数目和哲学家的数目相匹配 内景 左=位置; 内景 右=(位置+1)%%forks->size(); &