微软官宣:GSL 3.0.0发布

GSL 3.0.0 正式发布

我们高兴地宣布:C++ Core Guidelines Support Library (GSL)的微软实现3.0.0版本已经正式可用。gsl::span的微软实现在C++ 20 的span标准化进程中扮演着一个非常关键的角色。但是,标准中并没有包含用于内存边界安全的运行时检查。在微软的自身产品中,gsl::span所提供的内存边界安全特性成功地避开了一些安全问题。这次的发布版本在继续维护内存边界安全的同时,还对我们的实现进行了现代化升级,从而和C++ 20 span保持一致。

有哪些更新

> 新的gsl::span和gsl::span_iterator实现,保持与C++ 20标准的一致性。

> 对Contract Violation行为的更改。

> 添加CMake支持。

> gsl::multi_span和gsl::strided_span被标记为废弃。

在什么情况下我应该使用gsl::span,而不是std::span?

默认情况下,如果你已经启用了C++ 20模式并且不需要内存边界运行时检查,则可以使用VS2019 v16.6(在v16.7中,有一些额外的接口变更)自带的std::span。如果你需要支持C++ 20以下的版本(gsl::span支持C++ 14及以上)或者需要内存边界运行时检查(所有执行在gsl::span上的操作和它的迭代器都会有显式的边界安全检查)。

gsl::span

随着对span的标准化即将完成,我们决定是时候将我们的实现保持和标准设计一致了。在新的实现中提供了全功能的边界检查,确保了当底层数据有效时的边界安全。

主要的修改要点

gsl::span被重新实现主要是为了和标准的std::span保持一致。最大的变化是span的大小现在被定义为了无符号整数类型。之前我们使用的是std::ptrdiff_t这个类型,在新的实现中,我们改用了std::size_t来表示。另外对于它的扩展来说,dynamic_extent现在被定义为static_cast(-1),而不是之前的-1。

> span::size_type取代了原有的span::index_type。

> 添加了CTAD(Class Template Argument Deduction)支持。

接口一致性

在接口层面,还有如下的一些改动来保持gsl::span和std::span的一致性。

移除的函数

> span::operator

> span::at

> span::cbegin

> span::cend

> span::crbegin

> span::crend

新增的函数

> span::front

> span::back

重命名的函数

span::as_writeable_bytes被重新命名为span::as_writable_bytes

gsl::span_iterator的修改要点

在我们对span_iterator的新版实现中,我们彻底地重写了全部的代码,使之看起来更加像一个范围(range-like)。在之前的实现中,我们使用了一个span的指针和一个偏移,而在新版本中,我们使用了三个指针,它们分别是:begin, end和current。

新版实现的好处

新版实现自身可以执行所有的边界检查,而不是调用span。通过依赖指向底层数据的指针,而不是指向span的指针,新版的span_iterator可以拥有比底层span更长的生命周期。

新的头文件<gsl/span_ext>

有些用户可能会需要依赖旧版本的span实现,但是这些旧版实现在span的标准版实现中已经被移除了,为了支持这些用户,我们创建了新的头文件<gls/span_ext>。

从<gsl/span>中被删除的并加入到<gsl/span_ext>中的元素

> span comparison operators

> gsl::make_span

> span specialization of gsl::at

> gsl::begin

> gsl::rbegin

> gsl::crbegin

> gsl::end

> gsl::rend

> gsl::crend

契约违规

契约违规不再是可配置的。如果发生了违规,都会导致程序终止运行,而不是像之前那样可以通过提供编译器开关来抛出异常或者忽略违规。不过,这可能在将来的实现中发生改变。需要注意的是,移除抛出异常这种行为可能会要求我们将现有的测试套件从Catch2迁移到Google Test,因为Google Test可以在测试契约违规用例时更加容易的支持失效测试(Death Tests)。

CMake的改进

新版实现中现已支持find_package。一旦新版本完成安装,则可以使用find_package(Microsoft.GSL CONFIG)轻松找到GSL库。

关于multi_span和strided_span的废弃声明

为了将GSL的微软实现和C++ 核心规范(Core Guidelines)更好地保持一致,我们决定将gsl::multi_span和gsl::strided_span的实现声明为废弃。虽然现在我们还是会提供这些头文件,但是它们将不会再进行开发和维护,除非C++核心规范需要它们。

实现变更可能导致的编译失败及修复措施

变更:在gsl::span中,原来带符号的std::ptrdiff_t类型修改成无符号的std::size_t可能会导致带符号/无符号的不一致。修复措施:使用static_cast或者gsl::narrow_cast来解决这个不一致问题。

变更:gsl::multi_span和gsl::strided_span被声明为废弃。修复措施:以常量引用的方式传递多维数组,而不是使用gsl::multi_span。

变更:使用到了moved span帮助函数的代码可能会产生编译错误。例如span比较操作符,gsl::make_span等。修复措施:当你使用到这些函数的时候,请包含<gsl/span_ext>,而不是<gsl/span>。

变更:对契约违规抛出异常已经不再支持。修复措施:当应用程序终止运行之前,请使用一个终止处理例程来记录相关的诊断信息。对抛出异常这一行为的依赖将不再被确保是安全的。

总结

内存越界的确是一个很容易被忽略且难以诊断的问题,如果善用GSL,应该会显著的减少此类编码错误,进而提升产品健壮性。

微软官方网站

大家都在看

相关专题