C++17 详解 7

本文为 《C++17 in detail》 一书的中文渣中渣译文,不足之处还望指正。

2.3 过对齐数据的动态内存分配

当你用到 SIMD(Single Instruction,Multiple Data。单指令,多数据),或者有一些其它内存布局的要求时,你可能会需要特别地对齐数据。比如,SSE(Streaming SIMD Extensions)里你需要 16 字节对齐(AVX 256 里是 32 字节对齐要求)。你可以这样定义一个 vec4

1
2
3
4
5
class alignas(16) vec4
{
float x, y, z, w;
};
auto pVectors = new vec4[1000];

注:alignas 指示符在 C++11 引入。

译注:SSE 里数据对齐是必需的;到 AVX,数据对齐已经不是必要条件了,不过会损失部分性能。通常为适配不同硬件平台,可以不做对齐。

但是,C++11/14 没有保证内存是如何对齐的(译注:指动态分配的内存)。通常你不得不使用一些特殊的例程,比如 _aligned_malloc/_aligned_free 来确保维持对齐。这样做也不完美,因为它不能同 C++ 的智能指针一起工作,必须在代码里显式地做内存管理。

C++17 通过引入使用了对齐参数的几个额外的内存分配函数修复了这个漏洞:

1
2
3
4
5
6
void* operator new(size_t, align_val_t);
void* operator new[](size_t, align_val_t);
void operator delete(void*, align_val_t);
void operator delete[](void*, align_val_t);
void operator delete(void*, size_t, align_val_t);
void operator delete[](void*, size_t, align_val_t);

现在,你可以这样分配一个 vec4 数组:

1
auto pVectors = new vec4[1000];

代码没有变化,但是 vec4 的对齐已经被正确地处理了:

1
operator new[](sizeof(vec4), align_val_t(alignof(vec4)))

换句话说,new 现在知道对象的对齐方式了。

扩展:本修改提案:P0035R4

2.4 异常规范作为类型系统的一部分

函数的异常规范在过去不属于函数类型的一部分,现在是了。

现在你可以有两个重载的函数:一个带 noexcept,一个不带。

比如,下边的用例会导致编译错误:

1
2
3
4
void (*p)();
void (**pp)() noexcept = &p; // error: cannot convert to pointer to noexcept function
struct S { typedef void (*p)(); operator p(); };
void (*q)() noexcept = S(); // error: cannot convert to pointer to noexcept

添加此特性的原因之一,是允许做更进一步优化的可能性。当你保证一个函数是 noexcept 的,且它没有抛出任何异常时,优化就会产生。

译注:noexcept 不具有强制性,一个声明为 noexcept 的函数仍然可以 throw

另外,如上一章关于 语言修复 中描述,C++17 中的异常规范已经删除了已弃用的异常声明方式。事实上现在你只能通过使用 noexcept 指示符来声明一个函数可能会抛出异常。

扩展:本修改提案:P0012R1

2.5 编译器支持

略。

评论