在VS2015 Update 1中关于STL的修改

[原文发表地址] 在VS2015 Update1中关于STL的修改

[原文发表时间] 2015/12/7 9:20AM

VS 2015 Update 1 现在已经发布了,并且这个版本里包含了许多关于STL的修复。(这是自从2010 SP1起我们第一次将对STL的修改放到一个次要的版本上。在VS2015RTM 版本基本情况良好,没有出现严重的崩溃我们仅仅只是想尽快地向您分享我们的改进,并且我们内部的工序也将会使这变得更加容易) 通常,就像在2015RTM上的修复日志Part1Part2一样我会写一个详尽地更新日志。请注意,update 1里还包含和很多对编译器/集成开发环境等功能的改进(包括部分支持SFINAE表达式), 但是在这里暂不涉及这些- 毕竟我无法去亲自跟踪每一件事情。

首先,最近Steve Wishnousky 加入了VC类库小组,他已经在update 1上修复了两个bug:

* unordered_meow::max_bucket_count()这个函数返回了一个错误值(VS0#144294/Connect#1764567). 现在返回值正常。

* 我们的内部帮助函数 _Allocate() 和 _Deallocate()
因为不必要的模板化,生成了比必要模板化时更大的对象文件 (VS0#130290). 现在,他们将不再被模板化,这也使打包对象文件变得更加轻便简洁。

同样的,Hong Hong修复了出现在在<future>上的两个bug,这些bug 是因为在<future>的内部含有<ppltasks.h>等引起的。

*<future> 在不能支持_HAS_EXCEPTIONS=0 的情况下进行编译(TFS#1127004/Connect#1137364). 虽然这些问题目前在微软没有记录、验证和支持,但是不管怎样,我们还是最终决定把这些问题修复了。

* <future>间接定义了一个不规范的函数stdx::declval()(TFS#1194345/Connect#1494998)。这个目前已经被它重命名为Concurrency::details::declval()。(就目前来说,<future>引入 non-_Ugly Concurrency命名空间以及在此范围内的一些机制,这些都是我们期望的。)

接下来是我修复的一些bug:

* enable_shared_from_this<X>在调用
shared_ptr<volatile X>时会出现编译失败 (TFS#1184701) 。现在volatile可以像const那样正常运行。

* allocator_traits 错误地认为UserAlloc类的构造函数和析构函数返回空类型(在他们存在时),这将触发编译器在返回值非空类型时报错:(TFS#1184701)。现在我们能正确得接收(或者忽略)返回非空类型的场景。

* 在 2015 RTM的 tuple_size和tuple_element这两个类中, 我试图让static_asserting在处理关于non-tuple-ish的事情上更加有效。 遗憾的是, 这种改变妨碍到了SFINAE表达式, 这与文档中的相关说明是不一致的(TFS#1192603, TFS#1205400/Connect#1600812). 现在我们遵循标准文档.

* 规范规定在rethrow_exception()添加标记[noreturn],但是我们没有,这将会导致在编译的时候出现代码中断 (VSO#125155/Connect#1657472). 除了修复这个问题之外, 我还检查了其他所有可能发生缺失的地方 (没有任何地方遗漏), 并且我用[[noreturn]]代替了标准模板库中的每一个___declspec(noreturn)c。(它们是等同的, 所以这只是在可能的情况下用标准机制进行的一次简单尝试。 注意,在CRT上面还是继续使用_declspec。)

* 对于2015 RTM的 mem_fn()函数,我尝试通过函数调用约定来处理这种特别模糊的匹配调用 。然而 用户还是不可避免地发现这种修改对函数签名的影响其实是微乎其微的(VSO#134162).所以我放弃了这种方法,让men_fn()函数完全遵循标准文档。

* atomic<FunctionPointer>,
有时在使用来自C1XX却与 标准不一致用法的时候,这将会出现VC的前端编译问题(TFS#1181758/Connect#1393505). (这个问题是: 当对void * 和Object *进行强制类型转化的时候,
static_cast 和reinterpret_cast是等效的.然而, 在对void * 和Function *进行强制类型转化的时候, reinterpret_cast是可以正常作用的,但是static_cast 却是被禁用的, N4567 5.2.10[expr.reinterpret.cast]/8.) 因此现在<atomic>中使用reinterpret_cast来进行强制类型转化这是遵循标准文档的。

* 除了<atomic>这个之外,我还完善了STL 的头文件 (和测试用例) 可以让它们支持Clang/C2("具有Microsoft CodeGen 的语言编译器")。这也将支持Clang/LLVM。 从一开始,在我们的头文件中使用非标准调用的机率很小,这多亏了EDG(智能感应前端应用)这些年来严格地测试, 所以仅就这些头文件的改变是有必要的。作为这项工作的一部分,我也提交了许多关于Clang/C2的bug,因为这些已经在发布之前被修复了,所以你们在使用的时候将不会受到这些问题的困扰。这甚至鉴定了一些Clang本身的bug (例如type traits, 在原生字符串字面中的CRLFs), 并且确定了Clang本身改善的时机,这些修复也将会支持 在windows平台和非windows平台上的Clang/LLVM。特别感谢David Majnemer (非微软成员) 和其他在之前参与了这些bug的修复和改进的Clang 开发人员。

技术详情: Clang 3.7 附带了一对选项, -fms-extensions 和-fms-compatibility。 -fms-extensions 用来控制像__declspec(dllexport)这样的非标准特性, 这也是标准模板库要求完成的。 -fms-compatibility 控制"bug兼容性" (例如让Clang去模拟C1XX编译时的bug), 但是当我在和David在 CppCon 2015见面时, 我们意识到这里应该是有两种bug兼容性: 一种会影响ABI( (例如
layout) 的bug, 另一种是不会影响到ABI( (例如accepts-invalid)的bug. 所以这里我们在Clang's post-3.7 trunk(以及被移植到Clang/C2发布 )提交了一些改变. 目前, 当编译windows程序时,ABI相关的bug兼容性将会一直启用, 然而这个是需要用C1XX/C2库来作为链接编译的。。-fms-compatibility是用来控制和ABI无关的bug兼容性。我们的STL头文件(和测试代码) 需要和-fno-ms-compatibility选项一起运行, 从而保证高度的一致。(这里有一个例外:<future>引入<ppltasks.h>尽管这没有大的危害,但是会有一些与标准不一致的用法。标准文档中不允许不完整的类有返回值,即使这个返回值是来自一个已声明但未定义的虚假函数。当我发现这一情况的时, 已经来不及去在update1中修复了, 但意识到这一特定事件,Clang/C2在发布版之前先暂时剔除了。我已经在update 2上修复了<ppltasks.h>,所以在Clang/C2 上的解决方案最终也被移除了.)

* 与上面相近的问题, 我也修复了STL头文件支持/Za选项,并且添加完善的测试用例来覆盖测试。/Za 是用来启用拓展一致性的C1XX的 选项, 但是它通常也会引起在生僻代码路径下出现的拓展编译bug, 所以这一编译选项已弃用。(我在当/Za完全地破坏了vector<unique_ptr<T>>有效使用的时候, _虽然它最终被修复了,但是我迄今为止仍没有恢复这项测试。)

请注意, /Za 是一个编译器bug, 当你在STL中使用该选项时,会出现编译错误 (一般来说)。VSO#122298/Connect#1331482"__declspec(selectany) 常量表达式 和/Za选项不能一同运行"当多重转发单元插入到<limits>,的时候, 用/Za 编译constexpr将会触发链接错误,这在2015 RTM 版本已经被常量表达式化了 编译器已经在update 2上修复了这个bug。(我暂时将它放置在STL测试下, 我们只有一个关于多重转发单元的测试,非常可笑.)

* numeric_limits<float/double/long double>::infinity()/quiet_NaN()/signaling_NaN() 这些常量表达式,是由已经实施在C1XX和EDG上的GCC/Clang编译器的内建功能驱动。注意,signaling_NaN()明显受到一个C1XX bug (VSO#128935 /Connect#1686806)的影响,这个bug导致当他们从一个函数返回的时候,修改sNaN的bits,这种情况STL显然不能解决。

* <exception>函数有一些异常不能抛出,我已经添加进去了。

*shared_ptr的原子操作运算(怪异的免费函数, 不正常地操作)的一致性可以通过撤销一些冗余的拷贝来得到改善。

*Clang/libc++的测试套发现bitset<0> 的成员函数在运行时出现异常(TFS#917456, TFS#917467)。尽管bitset<0>仍然是没有意义的,但是现在起码它可以正常运行。

最后,尽管我不习惯去整理下编译器的修复列表,哪怕它是已经影响到STL(例如:<type_traits>),但这里还是有一个修改值得一提:

* Tanveer Gani 修复了bug VSO#103444 "常量表达式构造函数出现动态初始化"。这一问题已经 影响到了 最新常量化的STL,其中最重要的是std::once_flag这个现在已经按照标准规定的进行了静态初始化。请注意,这种修复是有一定的局限性,这种局限性是不允许他们破坏STL(例如虚函数含有虚函数的仍然不能进行静态初始化 ),并且这里还有一个可以被禁止的虚假警告-有关更多此问题的信息,请参见堆栈溢出问题中Tanverr的回答。

以上就是关于STL在Update 1中修改的全部内容。

Steve Wishnousky (@SteveWishnousky),我们的另一个新同事Billy O'Neal (@MalwareMinigun), 和我现在正着手于Update 2上更多的改变 – 我们已经提交许多修改和9个特性!(这将会是自从2008 SP1起我们第一次将STL的特性放到一个次要的版本上。)

Stephan T. Lavavej (@StephanTLavavej)

Visual C++类库高级工程师

stl@microsoft.com