如何在需要旧式unsigned char的地方使用新的std :: byte类型?

Vic*_*voy 31 c++ vector c++17

std::byte是C++ 17中的新类型,它是作为enum class byte : unsigned char.如果没有适当的转换,这将无法使用它.所以,我为这种类型的向量做了一个别名来表示一个字节数组:

using Bytes = std::vector<std::byte>;
Run Code Online (Sandbox Code Playgroud)

但是,它不可能在旧式中使用它:接受它作为参数的函数失败,因为这种类型不能轻易转换为旧std::vector<unsigned char>类型,例如,zipper库的用法:

/resourcecache/pakfile.cpp: In member function 'utils::Bytes resourcecache::PakFile::readFile(const string&)':
/resourcecache/pakfile.cpp:48:52: error: no matching function for call to 'zipper::Unzipper::extractEntryToMemory(const string&, utils::Bytes&)'
     unzipper_->extractEntryToMemory(fileName, bytes);
                                                    ^
In file included from /resourcecache/pakfile.hpp:13:0,
                 from /resourcecache/pakfile.cpp:1:
/projects/linux/../../thirdparty/zipper/zipper/unzipper.h:31:10: note: candidate: bool zipper::Unzipper::extractEntryToMemory(const string&, std::vector<unsigned char>&)
     bool extractEntryToMemory(const std::string& name, std::vector<unsigned char>& vec);
          ^~~~~~~~~~~~~~~~~~~~
/projects/linux/../../thirdparty/zipper/zipper/unzipper.h:31:10: note:   no known conversion for argument 2 from 'utils::Bytes {aka std::vector<std::byte>}' to 'std::vector<unsigned char>&'
Run Code Online (Sandbox Code Playgroud)

我试图表演天真的演员,但这也没有帮助.那么,如果它被设计为有用,它在旧的上下文中是否真的有用?我看到的唯一方法是std::transform在这些地方使用新的字节向量:

utils::Bytes bytes;
std::vector<unsigned char> rawBytes;
unzipper_->extractEntryToMemory(fileName, rawBytes);
std::transform(rawBytes.cbegin(),
               rawBytes.cend(),
               std::back_inserter(bytes),
               [](const unsigned char c) {
                   return static_cast<std::byte>(c);
               });
return bytes;
Run Code Online (Sandbox Code Playgroud)

这是:

  1. 丑陋.
  2. 需要很多无用的行(可以重写但仍然需要在之前编写:)).
  3. 复制内存而不是仅使用已创建的块rawBytes.

那么,如何在旧地方使用它?

The*_*ist 41

你错过了为什么一开始std::byte就被发明了.它被发明的原因是在存储器中保存一个原始字节而不假设它是一个字符.你可以在cppreference中看到它.

与char和unsigned char一样,它可以用于访问其他对象占用的原始内存(对象表示),但与这些类型不同,它不是字符类型,也不是算术类型.

请记住,为了安全起见,C++是一种强类型语言(因此在许多情况下隐式转换受到限制).含义:如果是从隐式转换bytechar是可能的,它会破坏目的.

所以,要回答你的问题:要使用它,你必须在你想要分配它时投出它:

std::byte x = (std::byte)10;
std::byte y = (std::byte)'a';
std::cout << (int)x << std::endl;
std::cout << (char)y << std::endl;
Run Code Online (Sandbox Code Playgroud)

其他任何东西都不能按设计工作!因此变换是丑陋的,同意,但如果你想存储字符,那么使用char.除非要存储默认情况下不应解释为char原始内存,否则不要使用字节.

而且你问题的最后一部分通常也是错误的:你不必复制,因为你不必复制整个载体.如果您暂时需要将a读取byte为a char,只需static_cast在需要将其用作a的地方char.它没有任何成本,而且是类型安全的.


至于在有关铸造评论你的问题std::vector<char>std::vector<std::byte>,你不能这样做.但是你可以使用下面的原始数组.所以,以下是一个类型(char*):

std::vector<std::byte> bytes;
// fill it...
char* charBytes = reinterpret_cast<char*>(bytes.data()); 
Run Code Online (Sandbox Code Playgroud)

它有一个类型char*,它是指向数组第一个元素的指针,可以在不复制的情况下取消引用,如下所示:

std::cout << charBytes[5] << std::endl; //6th element of the vector as char
Run Code Online (Sandbox Code Playgroud)

你得到的大小bytes.size().这是有效的,因为std::vector它在内存中是连续的.你通常不能用任何其他std容器(deque,list等)来做这件事.

虽然这是有效的,但它会从等式中消除部分安全性,请记住这一点.如果需要char,请不要使用byte.

  • 我会使用`static_cast <char*>(bytes.data())`而不是:) (10认同)
  • @Caleth和`std :: string`. (4认同)
  • 您也可以使用`std :: byte {10}`对其进行初始化. (2认同)
  • (仅)其他连续的`std ::`容器是`std :: array` (2认同)
  • @JiaHaoXu我没有建议这个,因为它非常危险,根本不安全.对模型进行模板特化是很常见的,这不能保证类的结构相同.使用内部阵列更安全. (2认同)
  • 转换对我不起作用的嗯:static_cast &lt;char *&gt;(&bytes.front())-我必须使用reinterpret_cast。那static_cast真的正确吗? (2认同)
  • @seanngpack 没有诸如“void char*”之类的东西。我认为你的意思是“char*”。您可以将 char* 数组复制到 std::byte 的新向量,但如果不复制数据则无法做到这一点。谷歌一下,你会发现一百万个例子。 (2认同)