Visual Studio 14 CTP1中C++ 14 STL特性、修复和破坏变化

我是微软的STL维护人员,我们再一次有一年的工作要告诉你。  (““我们”指的是P.J.Plauger的大多数功能,我自己的大多数修复和库问题解决方案,加上我们的库开发负责人Artur Laksberg和我们的CRT维护人员James McNellis提供的修复。)

null

如果你错过了 公告 ,你可以 下载VS14 CTP1 现在(注意他们说“在虚拟机中,或者在可用于重新格式化的计算机上”)和vs14rtm “最有可能在2015年某个时候上市” .

请注意,在这篇文章中,我将介绍2013 RTM和VS14 CTP1之间的变化——也就是说,这里列出的内容是VS14 CTP1中的新功能。  (例如, 编号3656 “makeu unique(修订版1)”在2013 RTM中发布,因此此处未列出。)

此外,“CTP”代表“社区技术预览”,但它的意思是 “阿尔法” .  请通过 微软连接 .

STL特征

我们已经实现了以下功能,这些特性被投票到C++ 14,加上一个技术规范:

编号3642 /自定义项

编号3644 空正向迭代器

编号3654 引用()

编号3657 异构关联查找

编号3658 整数u序列

编号3668 交换()

N3670型 获取()

编号3671 双范围equal()/isu permutation()/mismatch()

编号3779 <复杂>UDL

编号3887 元组元素

N3940号 文件系统“V3”技术规范

请注意,由于缺少编译器支持,的运算符“if()重载的虚浮点值是#if 0”。  (问题是“如果”是一个关键字。  C++ 14表示,当操作符“If())被写为空格时,“如果”不会被当作关键字,所以没关系。  是的,这是个古怪的规则。)  编译器后来被修复为支持这个特殊规则,所以我在下一批更改中删除了#if 0–但是它们还没有签入,所以它们在VS14 CTP1中不可用。

还要注意,我们的V3机器仍然是在V2的命名空间std::tr2::sys中定义的。  那是因为我们在 N3803型 (2013年10月发布)是最新的草稿,它指定了一个占位符“待定”命名空间std::tbd::filesystem。  当前草稿 N3940号 (2014年3月发布)指定std::experimental::filesystem::v1,更改名称空间在我们的todo列表中。

此外,我们已经实现了以下的库问题解决方案,这些问题被投票到C++ 14:

LWG 2097型 应约束打包的任务构造函数

LWG 2104型 唯一锁定移动分配不应为noexcept

长荣2112 无法从派生的用户定义类

长荣2144 类型索引中缺少noexcept规范

LWG 2145型 错误类别默认构造函数

长荣2162 分配器u属性::最大u大小缺少noexcept

LWG 2174型 wstringu convert::converted()应为noexcept

LWG 2176型 服务提供商wstringu convert和wbufferu convert的特殊成员

长荣2187 向量缺少emplace和emplaceu back成员函数

LWG 2193型 标准库容器的默认构造函数是显式的

长荣2247 类型特征和标准::nullptr

长荣2268 在std::basicu string的成员函数assign的声明中设置默认参数

长荣2272 引用应该使用charu traits::eq进行字符比较

长荣2278 标准库类型的用户定义文本

长荣2285 生成反向迭代器

长荣2306 匹配结果::引用应为值类型&,而不是常量值类型&&

长荣2315 弱ptr应可移动

长征2324 插入迭代器构造函数应使用addressof()

长荣2329 带有匹配结果的regexu match()/regexu search()应禁止临时字符串

长荣2332 regex_iterator/regex_token_iterator应该禁止临时regex

长荣2339 第n元素中的措辞问题

长荣2344 quoted()与padding的交互不清楚

长荣2346 积分常数的成员函数应标记为noexcept

国标9 删除gets()

noexcept的故事有点复杂。  我们有内部的NO.No.Office和(不用于公共消费的)宏(当前不限于公共消费),它扩展到“抛出”(这又由编译器作为对Y-O-DESPECEC(NoFoPE)的同义词处理,与C++的98- 14的“抛出())标准语义不同。  这些宏应该扩展到No.Buffe,但是我们已经被一系列相对较小的编译器错误所阻止,主要涉及C++ 14的隐式NOT规则,而不是析构函数。  (由于STL的实现本身就很复杂并且应用广泛,因此它是对编译器特性的严格测试。)  好消息是,这些编译器错误已经被修复,我已经能够在下一批更改中将STL的宏切换到使用真正的noexcept(STL的所有测试都通过了)。  不幸的是,这在VS14 CTP1中不可用。  (此外,我们还在解决条件noexcept的问题,STL应该在一些地方使用它。  目前,我们的宏将扩展为零。)

至于GETSH(),它从C11和C++ 14中删除(注:C++ 14仍然包含C99标准库,但是从C11作为一个特殊的例外进行了这个改变),我们的CRT的仍然提供::GETSH(),但是我们的STL的不再提供STD::GETSH()。

我们还实现了一个优化,由编译器后端团队的ericbrumer提供。  编译器的自动矢量化非常喜欢高度对齐的内存,因此我们将std::allocator更改为自动返回高度对齐的内存以进行大的分配,在这种情况下,它可能会以最小的开销来交换不同的内存。  如果您好奇,我们目前使用的神奇数字是,我们将为4096字节或更大的分配激活此特殊行为,并将它们(至少)与32字节(256位)对齐,尽管我们绝对保留在将来对此进行修改的权利。  (目前,我们正在为x86和x64做这项工作,但没有为ARM做这项工作—由于在该平台上的过度一致性,我们还没有观察到性能优势。)  请注意,为了避免不匹配的噩梦,不能禁用此行为–无论您是否要求编译器自动矢量化,甚至发出AVX/etc.指令,都会激活此行为。

STL修复

当我写关于 VC 2013中的STL修复 继续在这里申请。  说到这里,在我写了那篇文章之后,我能够在2013 RTM中得到更多的修复,但是我从来没有找到时间回去更新那篇文章。  因此,为了完整起见,2013 RTM中提供的以下修复程序:std::bind()现在使用限定调用std::tie(),以避免与boost::tie()(DevDiv#728471)混淆/ 接#792163 ),并且std::函数的构造函数现在可以避免在内存不足时崩溃(DevDiv#748972)。

此外,我们认为我们已经修复了iostreams中的错误,它是错误的浮点,但在2013年RTM之前不久,我们发现了一个回归并恢复了更改。  我们正在为VS14再次研究这个问题,但是我们仍然意识到这个领域的问题。

现在,让我们看看VS14 CTP1中提供的修复程序。  我们有一个p进行了几次大修:

*时钟有几个问题。  高分辨率时钟不是高分辨率(DevDiv#349782/ 连接#719443 )稳定的时钟和CRT的时钟()不稳定/ 接#753115 ).  我们已经解决了这个问题,将高分辨率时钟作为稳定时钟的typedef(在标准允许的情况下),它现在由QueryPerformanceCounter()提供支持,这是高分辨率的,并且满足标准对稳定/单调性的要求。  因此,staid_clock::time_point现在是chrono::time_point(DevDiv#930226)的typedef/ 接#858357 ),尽管严格一致的代码不应假定这一点。  (N3936 20.12.7.2[time.clock.staddy]/1表示稳定的时钟::时间点是计时::时间点>。)  独立地,CRT的clock()用QueryPerformanceCounter()重新实现。  (请注意,虽然这是一个显著的改进,但它仍然不符合C标准的要求,即clock()返回“processor time”,这可能会导致进程变慢 或者更快 每物理秒超过一秒,这取决于正在使用的内核数。  我们的CRT维护人员James McNellis认为,像这样改变clock()的行为可能会破坏现有的代码——而且我完全同意,这太可怕了,无法改变。)  此外,我们还收到一个关于系统时钟的错误报告,询问它是否应该返回本地时间(取决于时区)而不是UTC(DevDiv#756378)。  这个标准对这个主题很模糊(20.12.7.1[time.clock.system]/1“类systemu clock的对象代表系统范围内实时时钟的挂钟时间”,哇,太有用了!)。  我们的实现使用GetSystemTimeAsFileTime(),它返回UTC。  在考虑了这个问题之后,我得出结论,UTC在这里是非常可取的(程序应该在任何地方使用UTC,只对用户I/O执行时区调整)。  我还询问了GCC/libstdc++和clang/libc++的维护人员,他们确认他们的实现也返回UTC。  所以,虽然我拒绝改变这种行为,但我在附近的时候改进了系统时钟的实现。  现在我们调用getSystemTimePreciseSFileTime(),当它在操作系统(Win8+)上可用时,它具有更好的分辨率。  请注意,CRT/STL的操作系统感知行为是自动的,不需要用户程序员的输入(即它不受宏控制)。

*的编译时正确性、运行时正确性和性能都得到了改进。  我们已经删除了最后一段x86内联汇编代码,用内部函数替换它以提高性能。  (在这些函数(x86的8字节原子)中,我们离优化还有一两条指令,因此我们已经向编译器后端团队请求了新的内部函数。)  我们修复了compareu exchange函数族中的几个运行时正确性错误。  首先,现在我们总是执行29.6.5[atomics.types.operations.req]/21“指定的映射,当只提供一个memoryu order参数时,success的值是order,失败的值是顺序,除了内存Š顺序ŠacqŠrel的值应替换为内存Š顺序Šacquire的值,而内存Š顺序Šrelease的值应替换为内存Š顺序Šreleased的值/ 接#817225 ).  其次,我们修复了atomic的compareu交换中的一个bug,在那里我们无条件地写入“expected”(DevDiv#887644)/ 接#819819 ),而/21说写必须是有条件的:“原子地,比较对象或this指向的内存内容是否与预期的相等,如果为真,则用预期的替换对象或this指向的内存内容,如果为假,用对象或此对象指向的内存内容更新预期内存的内容。“  此修复程序还提高了性能。  (请注意,这是特定于原子;原子不受影响。)  我们还修复了几个编译器错误。  现在每个原子都是原子的typedef,所以“atomic int atom(1729);”现在编译(DevDiv#350397)/ 连接#720151 ),我们修复了原子(DevDiv#829873)中的编译器错误/ 接#809351 ,德夫迪夫#879700/ 连接#817201 )挥发性原子/ 连接#811913 ).  最后,我们改进了原子构造的性能—29.6.5[atomics.types.operations.req]/5说“初始化不是原子操作”,但我们不必要地使用原子指令进行初始化。

没有特定顺序的单个修复:

*C++ 11的最小分配器接口是非常棒的,但是这意味着STL实现必须做额外的工作,以处理缺少C++ 03的冗长分配器接口(例如嵌套的ReBe结结构)的用户定义的分配器。  在2013年RTM(多亏了可变模板)中,我们完成了使最小分配器适应详细接口所需的机制,但我们并没有在整个STL中始终使用它(DevDiv#781187)/ 接#800709 ).  所以对于vs14ctp1,我们审核了整个STL并修复了所有问题,所以现在任何需要分配器的东西都将接受最小的接口。  值得注意的是,std::function、sharedu ptr/allocateu shared()和basicu string是固定的。

*多亏了Filesystem V3,我们现在可以处理形式为serverdirectoryfilename.txt(DevDiv#512571)的网络路径/ 接#770316 第706628页/ 连接#788976 ).

*的duration%%duration、duration%%rep和duration/rep已经按照标准进行了修改,以前它们在各种情况下都无法编译(DevDiv#742944)/ 连接#794649 ).

*STL现在支持 /Gv编译器选项 (/Gd、/Gr和/Gz已经得到支持),以及显式标记为u vectorcall(DevDiv#793009)的函数/ 接#804357 ).  我们通过在/Gv下包含所有STL头来验证前者。  对于后者,uu vectorcall将在uu stdcall/etc.工作的任何地方工作,而不是在任何地方(由一个单独的bug跟踪,仍然处于活动状态)。

*STL现在支持 /Zc:strictStrings编译器选项 (德夫迪夫784218)。  C++ 03允许(但ISO不可)从字符串文字转换为可修改的字符**。  C++ 11移除了这个转换,//ZC:StultStand强制执行这个禁止。  虽然/Zc:strictStrings当前默认处于关闭状态,但我强烈建议使用它。

*2006年,的实现以一种模糊但极其有害的方式遭到破坏,具体到调试模式下的x64(DevDiv#447546)/ 接750951 第755427页/ 接#796566 ).  使用自定义分配函数(包括全局替换的操作符new/delete()),自定义分配的facet将被free()释放,然后世界将爆炸。  我最终弄清楚了问题的全部范围,并彻底根除了它。

*结合襄樊的编译器修复,我们改变了STL的头文件,通过避免释放未使用的机器(DevDiv#888567),大大减少了对象文件的大小(和静态库的大小)/ 连接#820750 ).  这种未使用的机器通常被链接器丢弃,因此EXE/DLL的大小应该保持不变(尽管它们可能会经历一些小的改进)。  例如,当编译一个文件(对于x86/MD /O2),包括所有C和C++标准库头并与之无关,VS 2013发出731 KB对象文件,而VS14 CTP1发出小于1 KB。

*C++ 11要求STL实现容忍操作员的过载地址。  VS2013的容器做到了,但不是所有的算法(DevDiv#758134)/ 接#797008 ).  此外,STL实现需要容忍重载的逗号运算符(“因为没有什么禁止它们”),这对于采用用户定义的迭代器并在for循环中使用“++iter1,++iter2”之类内容的算法来说是有问题的(DevDiv#758138)/ 接#797012 ).  我们已经审核了所有STL算法,以及迭代器强度的所有排列,以解决/comma问题。  我们已经修复了所有这些问题(通过添加一些addressof()调用和eleventy zillion(void)强制转换),并添加了一个测试来确保它们保持不变。

*自2005年以来,我们已经发布了调试检查,检测并抱怨STL算法的无效输入(如转置迭代器)。  然而,它们有点过于激进,抱怨将空指针作为迭代器传递,即使标准说它们完全有效。  例如,将两个[null,null]范围合并到一个null输出是有效的no-op。  我们已经审核了每个STL算法,并修复了它们的调试检查,以接受作为迭代器有效传递的空指针,同时仍然拒绝空指针的无效场景。  (例如,[非null,null)是一个伪范围。)  这解决了长期存在的bug报告(DevDiv#253803/ 接#683214 第420517页/ 接#741478 第859062页/ 接#813652 ).

* C++ 11的二进制搜索算法需要处理异构类型,其中范围元素和给定值的类型可以不同,并且范围元素可能甚至不能互相比较。  我们在几年前修复了下限()和上限(),但错过了相等的范围()(DevDiv#813065)/ 接#807044 ).  我们在EngalSangeReo()中留下了一个C++ 03时代的调试检查,这是有坏的两个原因:(1)它试图验证输入范围是排序的,但是C++ 11不需要元素<元素编译,(2)这是一个对数时间算法的验证,这是一个坏主意!  我们已经删除了违规的调试检查,因此,ErralSangeReo()现在符合C++ 11。  (但是,equal_range()仍包含另一个调试检查。  loweru bound()只给出elem

*我们更新了向量的接口,以符合C++ 14,添加EMPTIONE()、EMPANTION BULL()和(计数,OLLC)的构造函数(DeViDiα850453) 接#812409 ,也 长荣2187 ).

*我们无序的关联容器不能为单个元素的插入和复制提供有力的保证

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享