Visual Studio 2019版本16.0 现在可用 是吗 二进制兼容 在VS 2015/2017中,在VS 2019的第一个版本中,我们从C++ 20的工作文件中实现了更多的编译器和库特性,并实现了更多的功能。 <charconv>
重载(C++ 17的“最终boss”),并修复了许多正确性、性能和吞吐量问题。下面是C++ 17/20编译器/库特征工作和库修复的列表。像往常一样,许多编译器错误也被修复了,但是这里没有列出它们;编译器修复往往是特定于某些神秘的代码模式。我们最近在博客上 VS2019中的编译器优化和构建吞吐量改进 ,我们维护了一个关于 VS2019中的编译器一致性改进 .)
新功能:
- 实施 P1164页 从C++ 20无条件地。这就改变了
std::create_directory
检查失败时目标是否已经是目录。以前,所有ERROR_ALREADY_EXISTS
类型错误已转换为成功,但未创建目录代码。 - 迭代器调试功能已被教导正确地展开
std::move_iterator
. 例如,std::copy(std::move_iterator<std::vector<int>::iterator>, std::move_iterator<std::vector<int>::iterator>, int*)
现在我们可以开始行动了memcpy
快速通道。 - 标准库的宏化关键字执行
<xkeycheck.h>
固定的是发出实际问题关键字,而不是通用消息,寻找C++ 20关键字,并避免欺骗智能信息说随机关键字是宏。 - 我们补充道 长荣2221 的
operator<<(std::ostream, nullptr_t)
为了写作nullptr
把它变成溪流。 - 的并行版本
is_sorted
,is_sorted_until
,is_partitioned
,set_difference
,set_intersection
,is_heap
,和is_heap_until
由Miya Natsuhara实施。 - 第0883页 “修复原子初始化”,它改变了
std::atomic
初始化包含的值T
在我们的标准库中使用Clang/LLVM时实现了(也是由Miya实现的),而不是默认的初始化。对于c1x,这是当前禁用的,作为constexpr处理中的错误的解决方法。 - 实现了“太空船”的三向比较运算符 第0515页 “一致比较”,部分支持C++ 20
<compare>
标题如中所述 第0768页 (具体而言,比较类别和common_comparison_category
类型特征,而不是正在WG21中重新设计的比较算法)(由Cameron DaCamara在编译器中实现。) - 实现新的C++ 20 第1008页 聚合规则:具有用户声明的构造函数的类型(即使是默认的或删除的,以便不是用户提供的)不是聚合(由Andrew Marino在编译器中实现。)
- 实施
remove_cvref
和remove_cvref_t
类型特征来自 P0550型 ,这是方便剥离参考度和cv资格,但没有衰减函数和数组的指针(这是std::decay
和std::decay_t
是的)。 - C++ 17
<charconv>
浮点to_chars()
已改进:最短chars_format::fixed
速度快了60-80%(感谢谷歌的Ulf Adams建议的长除法),并且最短/精确chars_format::hex
已完成。最短固定记数法的进一步性能改进已经实施,并将在未来的VS2019更新中发布,同时将完成十进制精度重载<charconv>
实施。 - C++ 20 第0941页 特性测试宏现在在编译器和STL中完全受支持,包括
__has_cpp_attribute
由Phil Christensen实施。作为提醒,无论选择了标准模式选项,功能测试宏始终处于活动状态(即,已定义或未定义,取决于相关功能的可用性),因为使它们有条件于/std:c++latest
会在很大程度上挫败他们的目的。
正确性修复:
-
std::allocator<void>
,std::allocator::size_type
,和std::allocator::difference_type
已取消否决。 - 假的
static_cast
不是偶然压制的标准所要求的 C4244变窄警告 已从中删除std::string
. 正在尝试呼叫std::string::string(const wchar_t*, const wchar_t*)
现在将正确发射C4244“缩小awchar_t
变成一个char
.” - 固定的
std::filesystem::last_write_time
尝试更改目录的上次写入时间时失败。 -
std::filesystem::directory_entry
的构造函数被更改为存储失败的结果,而不是在提供不存在的目标路径时引发异常。 -
std::filesystem::create_directory
的2参数版本已更改为调用1参数版本,作为基础版本CreateDirectoryExW
功能将执行copy_symlink
当existing_p
是个符号链接。 -
std::filesystem::directory_iterator
当遇到断开的符号链接时不再失败。 -
std::filesystem::space now accepts
相对路径。 -
std::filesystem::path::lexically_relative
不再被后面的斜杠所迷惑,报告为 LWG 3096型 . - 四处工作
CreateSymbolicLinkW
拒绝中带有正斜杠的路径std::filesystem::create_symlink
. - 解决了Windows10LTSB1609上存在的POSIX删除模式删除功能,但实际上无法删除文件。
-
std::boyer_moore_searcher
和std::boyer_moore_horspool_searcher
的复制构造函数和复制赋值运算符现在实际上是复制对象。 - 并行算法库现在正确地使用了实数
WaitOnAddress
在windows8和更高版本上,而不是总是使用windows7和更早的假版本。 -
std::system_category::message()
现在从返回的消息中删除尾随空格。 - 一些可能导致
std::linear_congruential_engine
触发被0除已被修复。 - 我们在VS 2017 15.8中首次为程序员用户集成公开了迭代器展开机制(如中所述) https://devblogs.microsoft.com/cppblog/stl-features-and-fixes-in-vs-2017-15-8/ )不再展开从标准库迭代器派生的迭代器。例如,从
std::vector<int>::iterator
并尝试自定义行为现在在调用标准库算法时获取其自定义行为,而不是指针的行为。 - 无序容器保留函数现在实际上保留了N个元素,如中所述 LWG 2156型 .
- 许多STL内部容器函数都是私有的,以改善IntelliSense体验。在以后的版本中,还需要额外的修复程序将成员标记为私有 MSVC公司 .
- 传递到并发库的溢出时间(例如。
condition_variable::wait_for(seconds::max())
)现在已经得到了正确的处理,而不是在一个看似随机的29天周期内(当uint32被底层Win32 API接受的毫秒数溢出时)导致行为改变的溢出。 - 异常安全正确性问题,其中基于节点的容器
list
,map
,和unordered_map
如果修好的话会变得腐败。在propagate_on_container_copy_assignment
或propagate_on_container_move_assignment
在重新分配操作中,我们将用旧分配器释放容器的sentinel节点,在旧分配器上进行POCCA/POCMA分配,然后尝试从新分配器获取sentinel节点。如果此分配失败,则容器已损坏,甚至无法销毁,因为拥有sentinel节点是硬数据结构不变的。修复了这个问题,在销毁现有的sentinel节点之前,从源容器的分配器分配新的sentinel节点。 - 这些容器被固定为始终复制/移动/交换分配器
propagate_on_container_copy_assignment
,propagate_on_container_move_assignment
,和propagate_on_container_swap
,即使对于声明的分配器也是如此is_always_equal
. -
std::basic_istream::read
已修复为暂时不写入所提供缓冲区的部分,作为=>处理。这就放弃了我们在VS 2017 15.8中获得的一些性能优势,因为读取的大小大于4k,但是通过避免每个字符3个虚拟调用而提高的效率仍然存在。 -
std::bitset
的构造函数不再按相反顺序读取大位集的1和0。 - 实施时 P0083号 “拼接地图和集合”,我们设法忽略了
merge
和extract
除了接受左值容器的重载外,关联容器的成员还应具有接受右值容器的重载。我们已经通过实现rvalue重载纠正了这个疏忽。 - 随着 只是我的代码步进 特点,我们不再需要为客户提供定制化机械
std::function
和std::visit
达到同样的效果。移除该机器基本上没有用户可见的效果,只是编译器将不再生成在第15732480行或第16707566行上指示问题的诊断<type_traits>
或<variant>
. - 这个
<ctime>
标题现在正确声明timespec
和timespec_get
在命名空间中std
除了在全局命名空间中声明它们之外。 - 我们修复了
pair
的赋值运算符 长荣2729 “失踪的斯芬娜”std::pair::operator=
“; 它现在正确地接受可转换为配对的类型。 - 修正了一个小的type traits bug,其中addu const 等应该是一个非推断上下文(即它需要是
typename add_const<T>::type
,不是const T
).
标题包含:
标准库的物理设计进行了实质性的修改,以避免在不需要时包含头文件。许多客户希望使用标准库容器,但不希望使用iostreams和locale。但是,C++标准库在组件之间具有循环依赖性:
- 依赖于
<locale>
要使用的面std::string
作为其底层实现的一部分。 -
std::string
需要流插入运算符,这取决于std::ostream
,这取决于<locale>
.
- 历史上,我们的标准库通过引入较低级别的头来解决这个问题
<xstring>
,定义了std::string
,但其他内容<string>
.<xstring>
都会包括在内<locale>
组件,以及<string>
,还原定向依赖关系图。然而,这种方法有许多问题: -
#include <string>
需要拖入所有iostreams机器来提供流插入操作符,即使大多数翻译单元不使用流插入操作符。 - 如果只包括某人
<ostream>
他们得到了std::basic_string
和std::ostream
,但他们做到了 不 得到std::basic_string
的流插入运算符std::string
typedef或字符串文本。客户觉得这非常令人困惑。例如,如果有人试图流式传输std::basic_string
仅包括之后<ostream>
编译器会打印出一个非常长的诊断语句operator<<
找不到,列出26个不相关的重载。此外,尝试使用std::string_literals
,std::to_string
,或其他<string>
组件,将失败,这是混乱的时候std::basic_string
在其他方面是可用的。
在VS2019中,我们完全不同地解析循环引用。流插入操作符现在可以找到必要的 ostream
使用参数相关查找的组件,允许我们将其与字符串放在同一位置。这就恢复了(的)适当的分层 std::string
在……下面 <locale>
组件),使使用 <string>
不需要拖拽整个iostreams机器。
如果你有很多 .cpp
包含的文件 string
做一些简单的事情,例如:
#include <stdio.h> #include <string> void f(const std::string& s) { puts(s.c_str()); }
在VS 2017 15.9中,这个程序在7980XE测试机上编译需要244毫秒(平均运行5次),而在VS 2019 16.0中,它只需要178毫秒(约占时间的73%)。
此外,看似不相关的标题 <vector>
他们被卷入了这场混乱。例如, vector
想扔吗 std::out_of_range
,来源于 std::runtime_error
,它的构造函数 std::string
. 我们已经为所有抛出站点提供了离线函数,因此 <stdexcept>
在里面 <vector>
是不必要的,已被删除。在VS 2017 15.9中,以下程序以前编译需要177毫秒,但现在只需要151毫秒(85%的时间):
#include <vector> void f(std::vector<int>& v) { v.push_back(42); }
这种更改的一个缺点是,可能需要添加一些没有包含正确头的程序 #includes
. 如果你说 std::out_of_range
在此之前,您可能需要 #include <stdexcept>
. 如果您使用的是流插入操作符,那么现在可能需要 #include <ostream>
. 这样,只有翻译单位才真正使用 <stdexcept>
或 <ostream>
组件支付编译它们的吞吐量成本。
性能和吞吐量改进:
-
if constexpr
在标准库中的更多位置应用,以提高吞吐量并减少copy
家庭,像这样的排列reverse
和rotate
,并在并行算法库中。 - STL现在在内部使用
if constexpr
即使在C++ 14模式下也减少编译时间。 - 并行算法库的运行时动态链接检测不再使用整个页面来存储函数指针数组,因为将此内存标记为只读被认为不再与安全目的相关。
-
std::thread
的构造函数不再等待线程启动,也不再在底层C库之间插入如此多的函数调用层_beginthreadex
以及提供的可调用对象。以前std::thread
将6个函数放在_beginthreadex
以及提供的可调用对象,该对象已减少到只有3个(其中2个是std::invoke
). 这也解决了一个模糊的定时错误,其中std::thread
如果系统时钟在某个时刻发生变化,则的构造函数将挂起std::thread
正在创建。 - 修复了中的性能回归
std::hash
我们在实施std::hash<std::filesystem::path>
. - 一些地方的标准库用来实现正确的捕捉块现在使用析构函数代替。这将导致更好的调试器交互-通过受影响位置的标准库抛出的异常现在将显示为从其原始抛出站点抛出,而不是我们的重新抛出。不是所有的标准库捕捉块都被消除了;我们希望在MSVC的后续版本中,catch块的数量会减少。
- 次优编码
std::bitset
由内部的条件抛出引起的noexcept
通过分解抛出路径来确定函数。 - 这个
std::list
和std::unordered_meow
家族成员在更多的地方内部使用非调试迭代器。 - 几个
std::list
成员被更改为在可能的情况下重用列表节点,而不是取消分配和重新分配它们。例如,给定list<int>
已经有3号了,打电话给assign(4, 1729)
现在将覆盖前3个列表节点中的int,并使用值1729分配一个新的列表节点,而不是取消分配所有3个列表节点,然后使用值1729分配4个新的列表节点。 - 标准图书馆呼叫的所有地点
erase(begin(), end())
已更改为呼叫clear()
相反。 -
std::vector
现在在某些情况下可以更有效地初始化和擦除元素。 -
<variant>
已被重构,使其更为优化器友好,从而生成更小更快的代码。最引人注目的是,std::visit
而内线现在成了好朋友。 - 为了提高可读性,我们已经将clang格式应用到STL的头文件中(还有其他手动更改,例如,将大括号添加到所有控制流。)
报告错误:
请让我们知道您对VS2019的看法。您可以通过IDE的报告问题报告错误,也可以通过web,在 开发者社区的C++选项卡 .
比利·奥尼尔、凯西·卡特和斯蒂芬·T。拉瓦维