随着 std::byte 标准化,我们什么时候使用 void* 什么时候使用 byte*?
With std::byte standardized, when do we use a void* and when a byte*?
C++17 将包括 std::byte
,一种用于一个原子可寻址内存单元的类型,在典型计算机上具有 8 位。
在此标准化之前,在指向 "raw" 内存时已经存在一些困境 - 在一方面使用 char*
/unsigned char*
还是在另一方面使用 void *
其他。现在,首选 void *
的原因之一已被删除 - std::byte
与 char
的含义不同;这是关于原始内存,而不是字符。
所以,我的问题是:在 std::byte
的日子里,关于什么时候比 void *
更喜欢它以及什么时候相反,什么是好的经验法则?
当然,当您处理旧代码或 C 代码时,您会受到它所接受内容的限制;我主要指的是新代码,您可以在其中选择所有类型。
首先,当您必须使用 C 库函数或一般来说使用任何其他 extern "C"
兼容函数时,void *
仍然有意义。
下一个 std::byte
数组仍然允许单独访问它的任何元素。换句话说,这是合法的:
std::byte *arr = ...;
arr[i] = std::byte{0x2a};
如果您希望能够允许低级别访问,例如,如果您想手动复制数组的全部或部分,这是有意义的。
另一方面,void *
实际上是一个 opaque 指针,从某种意义上说,您必须将它转换为(到 char
或byte
) 在能够访问其各个元素之前。
所以我的意见是,只要您希望能够寻址数组的元素或移动指针,就应该使用 std::byte
,并且 void *
表示不透明仍然有意义只会作为一个整体通过(很难实际处理 void *
)的区域。
但是 void *
的实际用例在现代 C++ 中应该变得越来越不常见,至少在高层是这样,因为那些不透明区域通常应该隐藏在更高层 类 中,并带有方法来处理它们。所以恕我直言 void *
最终应该限于 C(和旧的 C++ 版本)兼容性和低级代码(例如分配代码)。
std::byte
的动机是什么?
引用自 original paper;
Many programs require byte-oriented access to memory. Today, such programs must use either the char
, signed char
, or unsigned char
types for this purpose. However, these types perform a “triple duty”. Not only are they used for byte addressing, but also as arithmetic types, and as character types. This multiplicity of roles opens the door for programmer error - such as accidentally performing arithmetic on memory that should be treated as a byte value - and confusion for both programmers and tools.
本质上,std::byte
是 "replace" 在需要将原始内存作为字节处理时使用 char
类型,断言这是安全的按值、按引用、指针和在容器中使用时适用。
std::byte
does not have the same connotations as a char; it's about raw memory, not characters
正确,因此在处理内存中的字节(如字节数组)时,std::byte
应该优先于 char
类型。立即想到一些较低级别的协议数据操作。
What is a good rule of thumb, for the days of std::byte
, regarding when to prefer it over void *
and when it's the other way around?
我认为类似的指南现在和以前一样适用。在处理需要字节寻址能力的原始内存块时,char *
等比 void *
更受欢迎,我认为现在适用相同的逻辑,但更喜欢 byte *
而不是 char *
。 char *
更适合字符序列。
如果希望不透明地传递指针,void *
可能仍然最适合这个问题。 void *
本质上意味着 "point to anything",但是任何东西仍然是东西,我们只是还没有说什么。
此外,类型 uintptr_t
(和 intptr_t
)可能会作为备选方案考虑在内,当然这取决于所需的应用程序。
... I mostly mean new code where you get to choose all the types.
除了兼容性(您无法选择类型)之外,新代码通常对 void *
的使用非常有限。如果您需要基于字节的处理,请使用 byte *
.
(这是一个潜在的经验法则,它来自我的脑海,没有任何人宽恕。)
经验法则:何时使用哪种指针?
- 对文本字符序列使用
char *
,而不是其他任何内容。
- 在类型擦除场景中使用
void *
,即当指向的数据被键入时,但由于某种原因不能使用类型指针或它无法确定是否打字
- 使用
byte *
作为原始内存,没有迹象表明它保存任何类型化的数据。
上述情况的例外情况:
- 旧代码时也使用
void *
/unsigned char *
/char *
;或者当非 C++ 代码强制您使用 byte *
时。但是在执行此操作时,您仍然可以使用基于 byte *
的接口来包装此类使用,从而不会将这种情况暴露给其余的 C++ 代码。
例子
void * my_custom_malloc(size_t size)
- 错误
byte * my_custom_malloc(size_t size)
- 对
struct buffer_t { byte* data; size_t length; my_type_t data_type; }
- 错误
struct buffer_t { void* data; size_t length; my_type_t data_type; }
- 对
std::byte
不仅仅是关于 "raw memory",它是字节可寻址的原始内存 ,并为其定义了按位运算。
您不应该使用 std::byte
来盲目地替换 void*
。 void*
保留其用途。 void*
对处理代码的意思是“这是一个数据块,但我不知道这个数据是什么,我也不知道如何操作在上面.
当您需要内存块的字节地址时使用std::byte
并且只定义了按位运算来对该数据进行操作。
std::byte
没有 定义了常规的基本数学运算,例如 operator+
、operator-
或 operator*
。没错,下面的代码是非法的:
std::byte a{0b11},b{0b11000};
std::byte c = a+b; // fails, operator+ not defined for std::byte
换句话说,当不是处理代码业务内容时使用void*
。
std::byte 示例
就像我上面说的,你在 std::byte
上所能做的就是像 |
、&
和 ~
这样的按位运算。下面是一个使用 std::byte
的例子,注意你需要一个 C++17 编译器来编译这个例子,有一个 here 但你必须从下拉列表中选择 select C++17在右上角
#include <iostream>
#include <cstddef>
#include <bitset>
using namespace std;
void print(const byte& b)
{
bitset<8> p( to_integer<int>( b ) );
cout << p << endl;
}
int main()
{
byte a{0b11},b{0b11000};
byte c=a|b;
//byte d = a+b; // fails
print(c);
return 0;
}
C++17 将包括 std::byte
,一种用于一个原子可寻址内存单元的类型,在典型计算机上具有 8 位。
在此标准化之前,在指向 "raw" 内存时已经存在一些困境 - 在一方面使用 char*
/unsigned char*
还是在另一方面使用 void *
其他。现在,首选 void *
的原因之一已被删除 - std::byte
与 char
的含义不同;这是关于原始内存,而不是字符。
所以,我的问题是:在 std::byte
的日子里,关于什么时候比 void *
更喜欢它以及什么时候相反,什么是好的经验法则?
当然,当您处理旧代码或 C 代码时,您会受到它所接受内容的限制;我主要指的是新代码,您可以在其中选择所有类型。
首先,当您必须使用 C 库函数或一般来说使用任何其他 extern "C"
兼容函数时,void *
仍然有意义。
下一个 std::byte
数组仍然允许单独访问它的任何元素。换句话说,这是合法的:
std::byte *arr = ...;
arr[i] = std::byte{0x2a};
如果您希望能够允许低级别访问,例如,如果您想手动复制数组的全部或部分,这是有意义的。
另一方面,void *
实际上是一个 opaque 指针,从某种意义上说,您必须将它转换为(到 char
或byte
) 在能够访问其各个元素之前。
所以我的意见是,只要您希望能够寻址数组的元素或移动指针,就应该使用 std::byte
,并且 void *
表示不透明仍然有意义只会作为一个整体通过(很难实际处理 void *
)的区域。
但是 void *
的实际用例在现代 C++ 中应该变得越来越不常见,至少在高层是这样,因为那些不透明区域通常应该隐藏在更高层 类 中,并带有方法来处理它们。所以恕我直言 void *
最终应该限于 C(和旧的 C++ 版本)兼容性和低级代码(例如分配代码)。
std::byte
的动机是什么?
引用自 original paper;
Many programs require byte-oriented access to memory. Today, such programs must use either the
char
,signed char
, orunsigned char
types for this purpose. However, these types perform a “triple duty”. Not only are they used for byte addressing, but also as arithmetic types, and as character types. This multiplicity of roles opens the door for programmer error - such as accidentally performing arithmetic on memory that should be treated as a byte value - and confusion for both programmers and tools.
本质上,std::byte
是 "replace" 在需要将原始内存作为字节处理时使用 char
类型,断言这是安全的按值、按引用、指针和在容器中使用时适用。
std::byte
does not have the same connotations as a char; it's about raw memory, not characters
正确,因此在处理内存中的字节(如字节数组)时,std::byte
应该优先于 char
类型。立即想到一些较低级别的协议数据操作。
What is a good rule of thumb, for the days of
std::byte
, regarding when to prefer it overvoid *
and when it's the other way around?
我认为类似的指南现在和以前一样适用。在处理需要字节寻址能力的原始内存块时,char *
等比 void *
更受欢迎,我认为现在适用相同的逻辑,但更喜欢 byte *
而不是 char *
。 char *
更适合字符序列。
如果希望不透明地传递指针,void *
可能仍然最适合这个问题。 void *
本质上意味着 "point to anything",但是任何东西仍然是东西,我们只是还没有说什么。
此外,类型 uintptr_t
(和 intptr_t
)可能会作为备选方案考虑在内,当然这取决于所需的应用程序。
... I mostly mean new code where you get to choose all the types.
除了兼容性(您无法选择类型)之外,新代码通常对 void *
的使用非常有限。如果您需要基于字节的处理,请使用 byte *
.
(这是一个潜在的经验法则,它来自我的脑海,没有任何人宽恕。)
经验法则:何时使用哪种指针?
- 对文本字符序列使用
char *
,而不是其他任何内容。 - 在类型擦除场景中使用
void *
,即当指向的数据被键入时,但由于某种原因不能使用类型指针或它无法确定是否打字 - 使用
byte *
作为原始内存,没有迹象表明它保存任何类型化的数据。
上述情况的例外情况:
- 旧代码时也使用
void *
/unsigned char *
/char *
;或者当非 C++ 代码强制您使用byte *
时。但是在执行此操作时,您仍然可以使用基于byte *
的接口来包装此类使用,从而不会将这种情况暴露给其余的 C++ 代码。
例子
void * my_custom_malloc(size_t size)
- 错误
byte * my_custom_malloc(size_t size)
- 对
struct buffer_t { byte* data; size_t length; my_type_t data_type; }
- 错误
struct buffer_t { void* data; size_t length; my_type_t data_type; }
- 对
std::byte
不仅仅是关于 "raw memory",它是字节可寻址的原始内存 ,并为其定义了按位运算。
您不应该使用 std::byte
来盲目地替换 void*
。 void*
保留其用途。 void*
对处理代码的意思是“这是一个数据块,但我不知道这个数据是什么,我也不知道如何操作在上面.
当您需要内存块的字节地址时使用std::byte
并且只定义了按位运算来对该数据进行操作。
std::byte
没有 定义了常规的基本数学运算,例如 operator+
、operator-
或 operator*
。没错,下面的代码是非法的:
std::byte a{0b11},b{0b11000};
std::byte c = a+b; // fails, operator+ not defined for std::byte
换句话说,当不是处理代码业务内容时使用void*
。
std::byte 示例
就像我上面说的,你在 std::byte
上所能做的就是像 |
、&
和 ~
这样的按位运算。下面是一个使用 std::byte
的例子,注意你需要一个 C++17 编译器来编译这个例子,有一个 here 但你必须从下拉列表中选择 select C++17在右上角
#include <iostream>
#include <cstddef>
#include <bitset>
using namespace std;
void print(const byte& b)
{
bitset<8> p( to_integer<int>( b ) );
cout << p << endl;
}
int main()
{
byte a{0b11},b{0b11000};
byte c=a|b;
//byte d = a+b; // fails
print(c);
return 0;
}