VS 2013中的C++ 11/14 STL特性、修复和破坏变化

我是斯蒂芬T。Lavavej,在过去的六年半里,我一直在与Dinkumware合作,在Visual C++中维护C++标准库的实现。  离我上一篇VCBlog文章已经有一段时间了,因为准备发布我们最新的一批更改让我很忙,但现在我有时间写下我们所做的一切!

null

如果你错过了通知,你可以 下载2013预览版 马上!

注:在这篇文章中,每当我说“2013”没有资格,我的意思是“2013预览和RTM”。  我将明确提到什么时候预览和RTM之间的事情会出现。

快速总结

Visual C++ 2013中的STL 改进C++ 11的一致性 ,包括初始值设定项列表和可变模板 更快的编译时间 .  我们还实现了即将到来的C++ 14标准的功能,包括 使您独一无二 以及 透明算子函子 .

编译器功能

作为提醒,这里是C++ 11核心语言特性,这些特性已经添加到编译器中,在VisualC++ 2013预览中(除了 Visual C++ 2012的特点 ,当然):

*函数模板的默认模板参数

*委派施工人员

*显式转换运算符

*初始化器列表和统一初始化

*原始字符串文本

*可变模板

它们在“Visual C++编译器2012年11月社区技术预览”中可用(它们覆盖在我的 视频演练 )但是编译器团队从那时起已经取得了很大的进展。  也就是说,成吨成吨的bug已经被修复了——其中许多都是由Nov CTP的用户报告的(谢谢!)。

就像赫伯·萨特刚刚在 “C++的未来” 在构建会议上(与同伴) 博客文章 更多的C++ 11核心语言特性将在2013 RTM中实现:

*别名模板

*默认函数(rvalue引用v3除外)

*删除的函数

*非静态数据成员初始值设定项(NSDMI)

关于这个警告:“RValk V3引用”是指如何自动生成移动构造函数和移动赋值操作符的C++ 11规则,以及在声明移动时抑制自动生成的副本的规则。  从2013年预览版到RTM版之间没有足够的时间让编译器团队实现RTM级的质量。  因此,不支持使用=default请求memberwise move构造函数和move赋值运算符。  编译器团队敏锐地意识到这些东西的重要性,包括对STL的重要性,这是他们2013年后RTM的最高优先事项之一。)

此外,一些C99核心语言功能将在2013 RTM中实现:

*C99布尔

*C99复合文字

*C99指定初始值设定项

*C99变量声明

请看赫伯的公告 视频 / 邮递 更多信息,特别是2013年后RTM C++ 11/14一致性路线图 ,包括(包括许多其他东西)RValk引用V3、CONTXEPR和C++ 14通用lambDas。

STL特征

Visual C++ 2013预览中的STL已经完全转换为使用以下C++ 11特征:

*显式转换运算符

*初始值设定项列表

*作用域枚举

*可变模板

在2013年RTM中,该列表将扩展到:

*别名模板

*删除的函数

我说“转换过”是因为STL已经伪造(我想)模拟“将是一个更庄严的词”,这些功能只有库的解决办法,有不同程度的成功,自从Visual C++ 2008 SP1。  更详细地说:

*在核心语言中,显式转换运算符是一个通用功能–例如,可以使用显式运算符MyClass()。  但是,标准库目前只使用一种形式:显式运算符bool(),这使得类可以安全地进行布尔测试。  (普通的“operator bool()”是出了名的危险。)  以前,我们用操作符指针到-member()来模拟显式操作符bool(),这导致了各种各样的麻烦和轻微的低效。  现在,这个“假布尔”的变通方法已经被完全删除。

*我们没有试图模拟初始化列表,尽管我意外地允许一个破碎的/非功能的“初始化”列表列表标题在Visual C++ 2010中被传送,混淆了注意到它存在的用户。  它在Visual C++ 2012中被删除,以避免混淆。  现在编译器支持initializer list,又回来了,它实际上可以工作了,我们已经实现了所有std::initializeru list构造函数和标准库中强制要求的其他函数。

*作用域枚举是在Visual C++ 2012编译器中实现的,但是由于涉及编译器错误的CL/CLR的长故事,我们不能在STL中使用它。  在VisualC++ 2013中,我们能够去掉我们的伪范围内枚举(通过在名称空间中封装传统的无范围枚举来模拟,这是明显不完美的)。

*多年来,我们用两种不同的“人造可变”预处理器宏系统模拟可变模板–第一个系统反复包含子标题,而第二个系统(更优雅,至于爬行的恐怖去)消除了副标题,并取代他们的大反斜杠继续宏,由其他宏压印出来。  本应是真正可变的函数,如make u shared(args…),实际上是通过重载实现的:make u shared()、make u shared(arg0)、make u shared(arg0、arg1)等。  原本应该是真变量的类,比如tuple,实际上是用默认的模板参数和部分专门化实现的。  这使得我们可以在几年前为您带来make_shared/tuple/等,但是它有很多问题。  宏很难维护,因此很难在受影响的代码中找到并修复bug。  滥发太多的重载和专门化增加了编译时间,降低了智能感知。  最后是无穷大问题。  我们最初将过载/特化加在0到10个参数中,但是随着变量的数量从Tr1增加到C++ +0x的演变,到C++ 11的最终形式,在Visual C++ 2012中,我们将无穷大从10降低到5,以提高大多数用户的编译时间(我们提供了一种通过宏,x ViuaRixMax来请求10的旧极限)的方法。

在Visual C++ 2013中,我们彻底地消除了伪变量宏。  如果你想要50种类型的元组,现在就可以了。  此外,我很高兴地宣布,切换STL到真正的可变模板已经完成 缩短了编译时间 减少编译器内存消耗 .  在STL的开发过程中通常会发生的事情是,标准告诉我们实现更多的东西,所以我们这样做了,更多的东西需要更多的时间和更多的内存来编译(这可以通过正确使用预编译头来减轻)。  然后,编译器的测试人员注意到性能下降并抱怨,我以一副铁石心肠和问心无愧的态度回应,因为标准告诉我要这样做。  但在这种情况下,人造变量是如此令人难以置信的膨胀,删除他们造成了很大的差异。  (解析一个可变模板并不是免费的,但它比解析6或其他重载的模板便宜得多。)

随着编译器、STL及其依赖项(尤其是CRT和并发运行时)的修改,精确的数字会发生变化,但是当我签入最终的变量重写时,我运行了一些测试,可以共享具体的数字。  我的测试包括x86版本模式下的所有STL头。  我实际上没有使用任何东西,但是编译器仍然需要做大量的工作来解析所有的东西,并实例化STL本身使用的东西,因此这是一种合理的方法来测量在不广泛使用STL的情况下拖动STL的开销。  将Visual C++ 2012(默认为“x变量ValdIX最大值=5”)与Visual C++ 2013进行比较,预处理后的文件大小从3.90 MB减小到3.13 MB。  编译时间从2307ms减少到2029ms。  (我只测量了编译器前端;后端在没有优化的情况下花费了150-250毫秒,这里对此不感兴趣。  此外,出于复杂的原因,我将不在这里讨论,我排除了生成预处理翻译单元所需的相对较短的时间——但正如您所见,计算这些时间只会进一步增加差异。)  最后,我通过生成一个预编译头(PCH是编译器内存快照)来测量编译器内存消耗,该头也从40.2 MB减少到33.3 MB。  因此,STL更小,根据每个度量编译更快。  如果你必须增加你的变量ViaRixMax来让你的程序用Visual C++ 2012来编译,那么改进会更加戏剧化(对于完整性,我测量了VixAddiCixMax=10,分别为6.07 MB、3325 ms和58.5 MB)。

(注意:我在2013年3月底执行了这些度量之后,编译器团队已经对一些内部数据结构进行了重大修改。  因此,Preview中的编译器内存消耗,尤其是RTM,可能与我最初的度量有很大的不同。  然而,这并不影响我的结论:孤立地考虑,使用真正的可变模板可以改进每个度量。)

*该标准要求STL中的一些内容是alias模板。  例如,ratio_add,ratio<11,10>>必须是ratio<34,15>的别名。  以前,我们用包含“type”typedef(有时称为“other”)的结构来模拟别名模板。  这种解决方法将在2013年RTM中完全消除。

*该标准在整个STL中声明了100多个已删除的函数,通常是为了使类不可复制。  以前,我们用传统的C++ 98/03解决方案模拟:私有未实现声明。  在2013年的RTM中,我们将消除这种解决方法,将自由函数标记为=delete,并按照标准的要求使用=delete公开成员函数(除了类型u info,因为这个边距太窄而无法包含的可怕原因)。

您可能已经注意到,编译器列表中有一些特性不在库列表中。  原因很简单:并非所有的核心语言特性都对标准库有明显的影响。  例如,原始字符串文本不需要相应的标准库实现更改(尽管它们使更易于使用)。  类似地,统一初始化(不包括初始值设定项列表)和NSDMIs不会影响STL。  你可以说pairp{11,22},但这并不涉及我们这边任何新的或改变的机器。  至于默认函数,它们通常出现在STL for moves中,这(如我前面解释的)是编译器尚不支持的。  除了moves之外,还有一些默认函数,我们只是还没有更新它们,因为“正常”地实现它们几乎没有什么不良后果。  最后,函数模板的委托构造函数和默认模板参数不会明显影响标准库的接口,尽管我们在内部使用它们。  (有趣的是,它们的内部使用实际上是必要的——委托构造函数是实现pair的分段构造函数的唯一方法,函数模板的默认模板参数是约束tuple的可变构造函数的唯一方法。)

您可能还注意到我在标题中提到了C++ 14。  那是因为我们已经实现了下面的标准库特征,这些库已经被投票到C++ 14工作文件中:

*“透明算子函子”少<>、大<>、加<>、乘<>,等等。

*使u唯一(args…)和使u唯一(n)

*cbegin()/cend()、rbegin()/rend()和crbegin()/crend()非成员函数

*别名模板使无符号、衰减等(在RTM中实现,但不是预览)

( 请注意 在这个帖子的底部有一个常见问题,“Q1:为什么你在没有完成C++ 11核心语言的时候,你就要实现C++ 14标准库的特性?”

更多信息,请阅读我的建议 编号3421 “使算符函子更大<>”(Standardese投票通过), 编号3588 “使你独一无二”(背景), 编号3656 “使大学独一无二(第1版)”(Standardese投票通过),以及我提出的关于图书馆第2128期的决议“缺少全球功能cbegin/cend”,该决议与其他委员会一起被接受 编号3673 “C++库工作组准备发布Bristol 2013”。  (一个保证哈希

沃尔特E。Brown(与微软没有关联)在年提出了alias模板 N3546型 “转换特性ReDux”,这无疑是最佳的投票到C++ 14。  凡敢于质疑这一论断的人,将被判处五年刻苦劳动,以打字代替打字。

另外,James McNellis(现在维护我们的CRT)使用透明操作符函子将的大小减少了25%。  例如,sort(first,last)和sort(first,last,comp)以前几乎有重复的实现,只是在如何比较元素上有所不同。  现在,sort(first,last)只调用sort(first,last,less<>())。  这种清理后来扩展到各种内部头中实现的算法,加上隐藏在中的算法和中的成员算法。  (编译时改进的一小部分可能归因于此。)  James还参与了细粒度容器需求大修和下面提到的几个错误修复——谢谢James!

修复

这就是它的特点。  现在,为了修复。  这一次,我跟踪了Visual C++ 2012和2013之间的所有STL修复。  这包括通过 微软连接 ,以及内部报告的错误(无论是我发现错误时自己提交的,还是我们的测试人员提交的,还是其他Microsoft团队提交的)。  我的清单应该是详尽无遗的,除了几个例外:我不计算在我们的测试中提交的bug,当它们不涉及损坏的库代码时,我试着省略引入的(令人高兴的是,很少)bug,然后在2012年发布后修复,我不计算那些在库中报告但在编译器中实际解决的bug(例如,一些类型特征bug实际上是我们所依赖的编译器钩子中的bug)。  此外,这里只列出了正式归档的bug。  有时我们会注意到并修复数据库中从未存档的错误(例如,我注意到引用的行为不正确,并修复了该错误,但从未有人报告过)。  我除了提供连接错误编号外,还提供了我们的内部错误编号(例如DevDiv#1729),因此如果有人问我更多详细信息,我可以轻松查找错误。

有几次大修:

*的全部目标是极快的速度,它包含了许多函数的不必要的缓慢实现。  我们的编译器后端(代码生成)团队的何文磊对的实现进行了重大重写。  我们在所有体系结构(x86/x64/ARM)上的性能现在应该是最佳的,或者非常接近。  (德夫迪夫#517261/ 连接#770885 )

*与编译器更改一起进行了显著的修改。  (一些类型的特征,如ISSAREnter,可以用普通的C++代码实现。  其他类型特征,如isu constructable,必须依赖“编译器挂钩”来获得准确的答案。)  这修复了几乎所有已知的类型特征bug,包括isŠpod、isŠassignable和其他类型特征在void中的错误行为(DevDivŠ387795)/ 连接#733088 ,DevDiv#424157),是否为nullptr#t(DevDiv#417110)的Š标量行为不正确/ 接#740872 ),不使用仅可移动参数的结果(DevDiv#459824),类型特征的可构造家族与参考错误地行为(DevDiv#517460),许多类型特征在其他类型特征方面被错误地实现(DevDiv#520660;例如,isu moveu assignable定义为isu assignable,但我们的实现并没有做到这一点),alignedu union返回的存储类型不够大(DevDiv#645232)/ 接#781713 ),以及为具有不可访问析构函数的类发出虚假警告的对齐方式(DevDiv#688225)/ 接#786574 –在RTM中修复,但不是预览)。

*在C++ 98/03中,生命是容易的。  STL容器要求它们的元素是可复制的,可复制的,无条件地复制(C++ 03 23.1 [ LIB容器。要求] / 3)。  在C++ 11中,只引入了像UNQuYY-PTR这样的可移动类型和引入EMPTITYOBACK()的附加成员函数,容器的要求被改写为细粒度。  例如,如果您有一个列表并且您用emplaceu back(a,b,c)填充它,那么T需要是可破坏的(显然)并且可以从(a,b,c)构造,但是它不需要支持任何其他东西。  这对于用户来说基本上是很棒的,但是它需要实现者对细节的大量关注。  James在大修时修复了许多bug,但是正式报告的bug有vector(10)没有编译(DevDiv#437519),vector(first,last)的要求太严格(DevDiv#437541),容器移动构造函数对元素的要求太高(DevDiv#566619)/ 连接#775715 ),和map/unorderedu mapop[]要求V大于默认可构造值(DevDiv#577613)/ 连接#776500 ).

*2013 RTM将包含一个大修,实现别名模板(DevDiv#693707/ 连接#786967 )彻底修复了大量的漏洞(DevDiv#704582)/ 接#788745 只是冰山一角)。

然后是个别的错误修复:

*std::find()的实现有一个优化,可以在可能的情况下调用memchr(),但是find()同时调用memchr()时过于激进,导致了不正确的结果(DevDiv#316853)/ 接#703165 ),而称之为攻击性不够会导致次优性能(DevDiv#468500)/ 接757385 ).  我们重写了这个优化,使之在所有情况下都是正确的和最优的。

*缺少用于比较shared_ptr/unique_ptr和nullptr的运算符(DevDiv#328276)。  有些比较是由于临时表的构造而编译的,但是标准要求操作符的存在,如果你仔细观察,这是可以观察到的。  因此,我们添加了运算符。

*共享的未来可通过标准禁止的方式转换为未来(DevDiv#361611)。  我们阻止了这种转换。

*在中,subtract_with_carry的流式运算符执行“全移位”(在一次操作中将所有位从整数中移出),这会触发未定义的行为,实际上在ARM上不起作用(DevDiv#373497)。  我们现在遵循标准的规则,因此这适用于所有体系结构。

*获取numericŠlimits的静态常量数据成员的地址与/Za编译器选项(DevDivŠ376524)不兼容。  现在是了。

*提供了std::endl(DevDiv#380718)的不必要重载/ 接#730916 ).  虽然它们看起来没有引起任何问题,但我们消除了它们,因此只存在标准的强制重载。

*按照标准的要求,tuple_element>现在强制I 连接#738181 ).

*的目录迭代器返回的路径太短(DevDiv#411531)。  (注意递归目录迭代器工作正常。)  我们修复了如下目录迭代器 一九七五年 ,文件系统V2草稿。  (文件系统V3正在我们的雷达上,但它不会在2013 RTM中实现。)

*包含一个名为#Strcpy()(DevDiv#422681)的手写实现。  现在它使用CRT的字符串复制功能,并在内部传递对数组的引用,以提高安全性。

*的op<<()使用std::hexfloat,但是的op>>()没有(DevDiv#425415)/ 连接#742775 ).  现在是了。

*在以前的版本中,iostreams被更改为与/vd2编译器选项一起正常工作,但是这种机制有时会发出编译器警告。  编译器获得了一个新的pragma,#pragma vtordisp,iostreams现在使用它,避免了这种虚假警告(DevDiv#430814)。

*由于输入错误,_VARIADIC_MAX=7未编译(DevDiv#433643)/ 连接#746478 ).  我们修正了这个错误,后来彻底根除了机器。

*系统错误::what()的返回值不符合标准(DevDiv#453372)/ 连接#752770 ).  现在是了。

*codecvt one如果没有各种using声明(DevDiv#453373),就无法编译/ 连接#752773 ).  它不再需要这样的解决办法。

*由于括号放错了位置,的duration cast有时无法编译(DevDiv#453376)/ 接752794 ).  我们修正了括号。

*我们的测试在/clr下发现了一个非常模糊的死锁,当持有locale锁并抛出异常时(例如,当std::locale是从一个伪名称构造的)。  我们重新整理了代码来解决这个问题(DevDiv#453528)。

*在ARM上,我们意识到我们正在以一种多线程不安全的方式减少sharedŧptr/weakŧptr的refcounts(DevDiv 355917)。  (注意:x86/x64完全不受影响。)  尽管我们从未观察到崩溃或其他不正确的行为,即使在集中测试之后,我们也改变了减量以使用顺序一致性,这绝对是正确的(尽管可能比最佳的稍微慢一点)。

*该标准并不保证tupleu size可以用于tuple(或pairs或array)以外的事物。  尤其是tupleŠu size不能保证工作(DevDivŠ457214)/ 接753773 ).  我们没有静默编译并返回0,而是将实现更改为关于此类情况的静态断言。

*C++ 11表示,清单::Erasee()不应该使端迭代器失效(DeViDiOx 461528)。  这是std::list表示的物理结果,所以发布模式总是正确的,但是我们的调试检查抱怨无效。  我们修复了它们,因此它们现在认为要保留结束迭代器。

*使用标志regex::icase | regex::collate构造正则表达式会导致区分大小写的匹配,这与标准(DevDiv#462743)相反。  现在它的结果是不区分大小写的匹配。

*构造一个std::线程导致ŠCrtDumpMemoryLeaks()(DevDivŠ467504)报告的内存泄漏/ 接757212 ).  这并不是一个严重的、无限制的泄漏——所发生的是,内部数据结构的一次性初始化正在分配标记为“正常块”的内存(由泄漏跟踪机器观察),而且在CRT关闭时也没有被注册进行清理。  我们通过将此分配标记为“CRT块”(默认情况下不包括在报告中)并将其注册以进行清理来修复此问题。

*对从打包的任务中获得的未来调用wait_for()/wait_until()将返回future_status::deferred immediate,这是不应该发生的(DevDiv#482796)/ 接#761829 ).  现在,它根据标准的要求返回futureu status::timeout或futureu status::ready。

*C++ 11的最小化分配器接口不需要分配器提供嵌套的ReNe结结构,但VC没有正确实现这个(DeViDi)483844。 接#762094 ).  我们已经按照标准安装了这个模板机器, N3690型 17.6.3.5[allocator.requirements]/3:“如果allocator是SomeAllocator形式的类模板实例化,其中Args是零个或多个类型参数,并且allocator不提供重新绑定成员模板,则默认情况下,标准allocatorU traits模板使用SomeAllocator代替allocator::rebind::other。对于不是上述表单的模板实例化的分配器类型,不提供默认值。“

*另一个最小化的分配器接口错误-在调试模式下,std::vector直接使用分配器,而不是通过分配器特性,这导致最小分配器不工作(DevDiv#483851)/ 接#762103 ).  我们修复了这个问题,并审核了所有容器以排除类似问题。

*为std::condition_变量供电的并发运行时中的一个bug导致崩溃(DevDiv#485243)/ 接#762560 ).  ConcRT解决了这个问题。

*人类永恒的敌人vector在x86上崩溃,指数超过20亿(DevDiv#488351)/ 接#763795 ).  请注意,20亿压缩位仅占用256MB,因此这是完全可能的。  我们修正了我们的数学,这样就行了。

*指针没有使用用户定义的空指针(DevDiv#491103)编译/ 接#764717 ).  我们重新设计了实现,这样就可以编译(而不是试图形成void&这是禁止的)。

*尽管根据标准它是正确的,merge()的实现执行的迭代器比较比需要的要多(DevDiv#492840)。  我们将此(及其相关实现)更改为最佳。

*timeŠput的返回值对于char是正确的,但是对于wcharŠt是不正确的,因为实现无意中发生了分歧(DevDivŠ494593)/ 接#766065 ).  现在wchar像char一样工作。

*C++ 11表示ISTrAMBufyItAuth::操作符*()应该按值返回图(DeViDi 494813)。  现在我们这样做。

*从setlocale()返回的const char*构造std::locale可能会崩溃,因为std::locale的构造函数在内部调用setlocale()!  (德夫迪夫#496153/ 接#766648 )  我们通过总是将构造函数的参数存储在std::string中来解决这个问题,它不能像这样无效。

*的独立u bits u引擎和shuffle u order u引擎在其构造函数(DevDiv#502244)中没有调用它们的u Init()助手函数/ 接#768195 ).  那很糟糕。  现在我们好了。

*pow(-1.0,complex(0.5))走了一条错误的捷径,返回NaN而不是i(DevDiv#503333)/ 接#768415 ).  我们修好了捷径。

*从nullptr构造共享的Šptr是分配一个引用计数控制块,这是标准(DevDivŠ520681)所禁止的/ 连接#771549 ).  现在这样的共享资源真的是空的。

*该标准对unique的操作顺序(DevDiv#523246)非常严格/ 连接#771887 ). N3690型 20.9.1.2.5[unique.ptr.single.modifiers]/4:“void reset(pointer p=pointer())noexcept;效果:将p赋给存储指针,然后如果存储指针的旧值oldu p不等于nullptr,则调用getu deleter()(oldu p)。[注意:这些操作的顺序很重要,因为对getu deleter()的调用可能会破坏*this-“尾注]”  我们现在完全遵循标准。

*有趣的是,标准允许iostream绑定到它们自己,但这在我们的实现中触发了堆栈溢出(DevDiv#524705)/ 接#772293 ).  我们现在可以检测自我捆绑并避免碰撞。

*标准要求minmax_element()来查找 最后的 最大元素(DevDiv#532622),与查找第一个最大元素的maxŠu element()不同。  这个选择不是武断的——它是minmaxu element()实现的基本结果。  我们修复了minmax_element()以遵循标准,并仔细审核了它的正确性。

*我们的实现将put#u time()声明为taking tm*(DevDiv#547347/ 连接#773846 ).  现在它需要const tm*作为标准的要求。

*在2012年11月的CTP中,在我们的标准库更改准备就绪之前发布,编译器团队提供了一个“假”头。  这基本上工作正常,只是文件末尾没有换行符,这激怒了/Za编译器选项(DevDiv#547397)/ 连接#773888 ).  现在我们有了来自Dinkumware的“real”,我们已经验证了在末尾有一个新行。

*system_clock::to_time_t()尝试执行舍入,但在给定大量输入时触发整数溢出(DevDiv#555154)/ 接#775105 ).  在标准允许的情况下,我们现在执行截断,使我们不受整数溢出的影响。

*该标准规定前向迭代器标记不应派生自输出迭代器标记(DevDiv#557214)/ 连接#775231 ),但在我们的实现中确实如此。  我们已经停止这样做了,我们已经改变了代码的其余部分来补偿。

*由于与运算符fake-bool()交互的一个模糊编译器错误,带有lambda deleters的唯一ptr并不总是布尔可测试的(DevDiv#568465)/ 连接#775810 ).  现在unique_ptr有了显式操作符bool(),这个bug已经被彻底根除了。

*在Visual C++ 2010和2012之间,我们引入了一个回归,其中解析带有IoFikes的浮点数(例如“ISS> dBL”)会得到最后一个错误,而CRT的STROTD()不受影响。  我们修复了iostreams以获得所有正确的位(DevDiv#576315)/ 连接#776287 ,也称为DevDiv#616647/ 连接#778982 –在RTM中修复,但不是预览)。

*的mt19937断言0不是有效的种子(DevDiv 357418)/ 连接#776456 ).  现在它被认为是有效的,正如标准所说。  我们修复了所有引擎以接受0个种子并生成正确的输出。

*的二进制重载没有像一元重载那样受到约束,在不清楚的情况下会导致编译器错误(DevDiv 357433)/ 连接#776471 ).  虽然标准不要求这样做,但是我们已经限制了二进制重载,这样它就可以工作了。

*inplaceu merge()是标准中为数不多的非常特殊的算法之一–它分配额外的内存以完成其工作,但是如果它不能分配额外的内存,它会退回到较慢的算法,而不是失败。  不幸的是,我们实现的回退算法是不正确的(DevDiv#579795),这在很长一段时间内没有引起注意,因为在21世纪没有人会耗尽内存。  我们修复了inplaceu merge()的回退算法,并审核了所有回退算法的正确性(包括稳定性)。  我们还添加了回归测试(能够根据需要将Vulcan神经夹送到operator new()/等),以确保这种情况不会再次发生。

*由于一个off by one错误,future_errc的message()和what()不起作用(DevDiv#586551)。  这是在标准开始说未来的u errc不应该从0开始时引入的,我们相应地更改了实现—但没有注意到消息翻译仍然假设基于0的索引。  我们已经修好了。

*basic的regex实现允许在旧的错误修复后直接或在字符范围内使用高位字符,但它拒绝通过regex十六进制转义直接或在字符范围内指定的高位字符(DevDiv#604891)。  现在两者都是允许的。

*标准要求由空函数指针、空成员指针和空std::函数构造的std::函数为空。  我们的实现是构造存储空函数指针等的非空std::函数,调用时会崩溃。  我们按照标准(DevDiv#617384)对此进行了修复/ 连接#779047 –在RTM中修复,但不是预览)。

*由于模板元编程的微妙性(DevDiv#643180),指针u traits>无法工作/ 接#781594 )–编译器确实不希望看到由值返回的抽象类,即使我们只是为了decltype而这样做。  我们已经修复了这个机器,所以它适用于抽象类。

*在某些情况下,我们的迭代器调试机制是先锁定,然后不执行操作,这是毫无意义的慢(DevDiv#650892)。  这发生在两种情况下:_ITERATOR_DEBUG_LEVEL=1(这从来不是默认值)和deque。  我们已经修复了这个问题,所以只有在有实际工作需要保护时,才会在_ITERATOR_DEBUG_LEVEL=2中使用锁。

*C++ 11表示,列表::SPLICE()不使迭代器无效,它只传送受影响的迭代器(DeViDiα671816)。 连接#785388 ).  这是一个物理保证,但是我们的调试检查认为这样的迭代器是无效的。  我们已经更新了检查,所以他们严格遵循C++ 11的规则。  (注意:forwardu list::spliceu after()仍受影响;我们计划在将来解决这个问题,但不是在2013年

*中align()的实现没有遵循标准(DevDiv#674552)。  现在是了。

*Lambdas捕获引用包装器在某些情况下不会编译(DevDiv#704369/ 接#788701 ).  既然我们已经修复了referenceu wrapper中的一致性问题,那么这段代码就可以干净地编译了。

*按下空格键(xkcd#1172)时,cin不再使CPU过热。

突破性变化

在这一点上,这些特性和修复源于源代码更改——即使在使用Visual C++ 2012编译的情况下,您也必须更改代码以符合C++ 11。  下面是一个非详尽的列表,所有这些都已在实际代码中观察到:

*调用std::min()或std::max()时,必须#包括

*如果您的代码确认了我们的假作用域枚举(包装在名称空间中的传统非作用域枚举),则必须对其进行更改。  例如,如果您指的是类型std::futureu status::futureu status,那么现在您必须说std::futureu status。  请注意,大多数代码不受影响—例如,std::futureu status::ready仍然可以编译。

*类似地,如果您的代码确认了我们的假别名模板,则必须将其更改为2013 RTM。  例如,您必须说allocatorU traits::rebindU alloc::other而不是allocatorU traits::rebindU alloc。  有趣的是,尽管ratio_add::类型将不再是必需的,您应该说ratio_add,但前者将继续编译。  这是因为ratio需要有一个“type”typedef来表示一个缩减的ratio(如果已经缩减了,那么它将是相同的类型)。

*显式运算符bool()比运算符fake-bool()严格。  显式运算符bool()允许显式转换为bool(例如,给定共享的ptrsp,静态u cast(sp)和bool b(sp)都有效)和“上下文转换”为bool(这些是布尔可测试的场景,例如if(sp)!sp,sp&&随便什么)。  但是,显式运算符bool()禁止隐式转换为bool,因此不能说bool b=sp,也不能说return sp;给定布尔返回类型。

*现在我们使用的是真正的可变模板,我们没有定义可变的最大值及其未指定的共谋者。  如果您仍在定义变量最大值,我们不会抱怨,但不会有任何影响。  如果你承认我们的人造可变模板宏机器在任何其他方式,你必须改变你的代码。

*除了普通的关键字,STL头现在严格禁止对上下文敏感的关键字“override”和“final”进行宏化。

*referenceu wrapper/ref()/cref()现在严格禁止绑定到临时对象。

*现在严格执行其compiletime前提条件。

*各种STL类型特征都有一个前提条件:T应是一个完整的类型。  现在编译器更严格地执行了这一点,尽管我们不能保证它在所有情况下都是强制执行的。  (STL前提条件冲突会触发未定义的行为,因此该标准不保证强制执行。)

*STL不尝试支持/clr:oldSyntax.

常见问题

Q1:为什么你还没有完成C++ C++ 14标准库的功能,而你还没有完成C++ 11核心语言呢?

A1:这个问题问得好,答案很简单。  我们的编译器团队非常清楚C++ 11核心语言的特点,这些功能有待于实现。  我们在这里实现的是C++ 14标准库的特性。  编译器开发人员和库开发人员是不可互换的——如果我的生命依赖于它,我就无法实现主要的编译器功能(即使是静态的断言也要花费我几个月的时间才能弄清楚),我喜欢认为情况正好相反,尽管火箭科学家可能比火箭科学的比萨饼送货员更擅长比萨饼送货。

问题2:很公平,但您之前提到了“C++14通用lambdas”。  为什么您的编译器团队计划实现 任何 C++ 14内核语言特点在整理前 全部的 C++ 11核心语言的特点?

A2:正如赫伯喜欢说的那样,“C++ 14完成C++ 11”。  编译器团队正在追求完全C++ 14的一致性,并将所有C++ 11和C++ 14的特性看作是统一的工作项桶。  他们正在根据客户需求(包括库需求)和实现成本对这些功能进行优先级排序,以便尽快交付最有价值的功能。  功能的优先级不受其在工作文件中的投票时间的影响。  因此,他们的后3-RTM一致性路线图在价值较低的C++ 11特征(例如属性)之前放置了非常有价值的C++ 14特征(例如通用lambda)。  再说一遍,请看赫伯的公告 视频 / 邮递 更多信息。

Q3:C99标准库通过引用合并到C++ 11中的情况如何?

A3:好消息——我的同事Pat Brenner和Dinkumware一起胡选了大量的C99,并将它们集成到Visual C++ 2013的CRT中。  我们还没有完成,但我们正在取得进展。  不幸的是,我没有时间处理STL中相应的包装头(包装)。  时间非常有限,我选择把时间花在签入可变模板重写上。  我也许可以把包装头放到2013 RTM中,但我还不能保证。

Q4:这些编译器/库特征将在Visual C++ 2012更新中进行,还是我们必须等待Visual C++ 2013?

A4:你必须等待Visual C++ 2013。  我知道这不是大多数人想听到的,所以请允许我解释一下。

我是个程序员,如果你在读这篇文章,我想你也是个程序员。  所以,作为程序员,让我们一起来看看下面的区别。  这是UTUPLE >从Visual C++ 2012到2013的变化,正如我们的内部差异工具“奇”所看到的:

图片[1]-VS 2013中的C++ 11/14 STL特性、修复和破坏变化-yiteyi-C++库

请特别注意左侧的视觉摘要。  从技术上讲,这个差异是 可怕的怪物 的代码现在已经非常棒了,但要达到这一点所需的更改基本上是完全重写的。  和其他头收到了类似(但较少)的更改。

VS-Update机制主要用于发布高优先级的错误修复,而不是发布新特性,特别是带有中断性更改的大规模重写(与同样大规模的编译器更改相关)。

像Visual C++ 2013这样的主要版本给了我们改变和打破很多东西的自由。  我们根本不可能在更新中发布这些东西。

问题5:那些错误修复程序呢?  我们能更新一下吗?

A5:这是一个有趣的问题,因为答案取决于我的选择(而在上一个问题中,即使我愿意,也不允许我在更新中进行这样的重写)。

每个团队都可以选择将哪些错误修复带到“shiproom”,以便考虑将其包含在更新中。  有些事情shiproom不会让我们逃脱(例如,在主要版本之外禁止二进制破坏性的更改),但否则我们就有了决定事情的自由。  我个人优先考虑带宽而不是延迟——也就是说,我更喜欢在每个主要版本中发布更多的错误修复,而不是在多个更新中更频繁地发布更少的错误修复(在同一时间段内)。

更详细地说,backporting修复需要非零的时间(特别是当分支由于累积的更改而出现分歧时)。  这也是更危险的——正如你所听到的,C++是一个复杂的世界,显然简单的改变会产生意想不到的后果。  即使它只是发出一个虚假的警告,我们也不希望更新破坏东西。  在主要版本中修复东西给了我们时间来修复补丁,让一切都完全正确。

我们经常备份STL修复(例如在Visual C++ 2010 RTM中,有一个STD::由小字符串优化导致的String内存泄漏

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