我应该用GSL跨度替换(void*,size)吗

Should I replace (void*, size) with a GSL span?

本文关键字:size void GSL 替换 我应该      更新时间:2023-10-16

假设我有

int foo(void* p, size_t size_in_bytes);

并且假设使CCD_ 1类型化是没有意义的。我想成为一名优秀的程序员并应用C++核心准则。具体来说,我想使用跨度而不是(*,len)对。嗯,span<void>不会编译(不能添加到void *);而span<char>span<uint8_t>等将意味着foo实际期望的是字符,而它可能不是。

那么,在这种情况下,我应该使用span<something-with-size-1>,还是坚持使用void*

这个问题没有一般的答案。

对于一个函数来说,它采用span<T>意味着它采用了一个连续的值数组,而没有任何形式的所有权转移。如果该描述不能合理地表示正在发生的事情,那么就不应该使用span<T>

例如:

如果函数检查缓冲区是否与我的内存空间中的一个区域相交,比如说,映射到一个文件,该怎么办?

这听起来不像foo0。听起来你应该有一个简单的聚合,它的名字能清楚地表明它的意思:

struct memory_region
{
void* p;
size_t size_in_bytes;
};

你甚至可以给它一个成员函数来测试交叉点。如果您正在制作一个用于处理此类内存区域的系统,我可能会建议使用构造函数等更封装的类类型。

函数的类型应该解释数据的含义。这个意思最好是一般意义上的,但至少,它应该说明它对所讨论的函数意味着什么。


还有一件事:

span<uint8_t>等都意味着foo实际上需要字符

不,不会。虽然uint8_t几乎肯定与unsigned char具有相同的大小,但这并不意味着期望能够将字符数组传递给任何使用span<uint8_t>的函数。如果该函数想宣传它接受字符,它会使用unsigned char


我的意思是说span<whatever>将意味着函数期望whatever

是的,spans的要求是向它传递给定大小的Ts的实际数组。

C++标准化委员会提出的建议是,如果你想传递一个指向字节序列的指针(这通常是人们传递void*时想要做的),那么你就传递一个span<std::byte>,它依赖于一个新的std::byte类型。然而,这需要对语言标准进行一点小小的修改才能合法。

在今天的C++中,您可以传递span<unsigned char>(您发现最具描述性的typedef'd),并获得相同的效果:访问一个字节序列。

我选择实现一个名为memory_region的类,它具有gsl::span的所有类型内特定功能(因此,例如,它没有begin()或end())。这是而不是与字节跨度IMO-在结构上我永远不会把它们混淆。

这是我的实现(它是与DBMS相关的GPU内核和我正在开发的测试框架的存储库的一部分,因此是与CUDA相关的片段;它取决于一些GSL,在我的情况下,我认为MS的GSL-lite也应该可以)。