我应该用 GSL 跨度替换 (void*, size) 吗?
Should I replace (void*, size) with a GSL span?
假设我有
int foo(void* p, size_t size_in_bytes);
并假设输入 foo
没有意义。我想成为一名优秀的编码员并应用 C++ 核心准则。具体来说,我想使用跨度而不是 (*, len) 对。嗯,span<void>
不会编译(不能添加到 void *
); span<char>
或 span<uint8_t>
等意味着 foo 实际上需要字符,但它可能不会。
那么在这种情况下我应该使用 span<something-with-size-1>
还是坚持使用 void*
?
这个问题没有统一的答案。
对于一个函数来说,它接受一个 span<T>
意味着它接受一个连续的值数组,没有任何形式的所有权转移。如果该描述不能合理地代表正在发生的事情,那么它不应该采用 span<T>
.
例如:
What if the function checks whether the buffer intersects a region in my memory space which is, say, mapped to a file?
这听起来不像 span<T>
。这听起来像你应该有一个简单的聚合,其名称可以清楚地表明它的含义:
struct memory_region
{
void* p;
size_t size_in_bytes;
};
你甚至可以给它一个测试交集的成员函数。如果您正在制作一个系统来处理此类内存区域,我可能会建议使用带有构造函数等的更封装的 class 类型。
函数采用什么类型应该解释数据的含义。最好这个意思是一般意义上的,但至少,它应该说明它对所讨论的功能意味着什么。
还有一件事:
or span<uint8_t>
etc. would imply foo actually expects chars
不,不会。虽然 uint8_t
几乎肯定与 unsigned char
具有相同的大小,但这并不意味着人们期望能够将字符数组传递给任何采用 span<uint8_t>
的函数。如果该函数想要宣传它接受字符,它会使用 unsigned char
.
I meant to say span<whatever>
would imply the function expect whatever
's.
是的,span
s 的要求是传递给定大小的 T
s 的实际数组。
C++ 标准化委员会的提议是,如果你想传递一个指向字节序列的指针(这通常是人们在传递 void*
时想要做的),那么你将传递span<std::byte>
,它依赖于新的 std::byte
类型。但是,这需要对语言标准进行小幅更改才能合法。
在今天的 C++ 中,您可以传递 span<unsigned char>
(typedef,因为您发现最具描述性)并获得相同的效果:访问字节序列。
我选择做的,以及我认为的,我们可以说,从设计的角度来看,是实现一个名为 memory_region
的 class,它具有所有特定于类型的功能gsl::span
的(因此,例如,它没有 begin() 或 end())。它 不是 与字节跨度相同的东西,IMO - 我在结构上永远不会把它们搞混。
这是我的 implementation(它是与 DBMS 相关的 GPU 内核和我正在处理的测试框架的存储库的一部分,因此是与 CUDA 相关的代码段;它依赖于一些 GSL,在我的我认为 MS'es 的 case gsl-lite 应该也可以。
假设我有
int foo(void* p, size_t size_in_bytes);
并假设输入 foo
没有意义。我想成为一名优秀的编码员并应用 C++ 核心准则。具体来说,我想使用跨度而不是 (*, len) 对。嗯,span<void>
不会编译(不能添加到 void *
); span<char>
或 span<uint8_t>
等意味着 foo 实际上需要字符,但它可能不会。
那么在这种情况下我应该使用 span<something-with-size-1>
还是坚持使用 void*
?
这个问题没有统一的答案。
对于一个函数来说,它接受一个 span<T>
意味着它接受一个连续的值数组,没有任何形式的所有权转移。如果该描述不能合理地代表正在发生的事情,那么它不应该采用 span<T>
.
例如:
What if the function checks whether the buffer intersects a region in my memory space which is, say, mapped to a file?
这听起来不像 span<T>
。这听起来像你应该有一个简单的聚合,其名称可以清楚地表明它的含义:
struct memory_region
{
void* p;
size_t size_in_bytes;
};
你甚至可以给它一个测试交集的成员函数。如果您正在制作一个系统来处理此类内存区域,我可能会建议使用带有构造函数等的更封装的 class 类型。
函数采用什么类型应该解释数据的含义。最好这个意思是一般意义上的,但至少,它应该说明它对所讨论的功能意味着什么。
还有一件事:
or
span<uint8_t>
etc. would imply foo actually expects chars
不,不会。虽然 uint8_t
几乎肯定与 unsigned char
具有相同的大小,但这并不意味着人们期望能够将字符数组传递给任何采用 span<uint8_t>
的函数。如果该函数想要宣传它接受字符,它会使用 unsigned char
.
I meant to say
span<whatever>
would imply the function expectwhatever
's.
是的,span
s 的要求是传递给定大小的 T
s 的实际数组。
C++ 标准化委员会的提议是,如果你想传递一个指向字节序列的指针(这通常是人们在传递 void*
时想要做的),那么你将传递span<std::byte>
,它依赖于新的 std::byte
类型。但是,这需要对语言标准进行小幅更改才能合法。
在今天的 C++ 中,您可以传递 span<unsigned char>
(typedef,因为您发现最具描述性)并获得相同的效果:访问字节序列。
我选择做的,以及我认为的,我们可以说,从设计的角度来看,是实现一个名为 memory_region
的 class,它具有所有特定于类型的功能gsl::span
的(因此,例如,它没有 begin() 或 end())。它 不是 与字节跨度相同的东西,IMO - 我在结构上永远不会把它们搞混。
这是我的 implementation(它是与 DBMS 相关的 GPU 内核和我正在处理的测试框架的存储库的一部分,因此是与 CUDA 相关的代码段;它依赖于一些 GSL,在我的我认为 MS'es 的 case gsl-lite 应该也可以。