std::byteできっちりバイト生活
C++で特定のバイト数のメモリを確保したい時は、昔からchar
かunsigned char
という型を使っていると思います。
例えば、以下のようにちょうど20バイトのメモリを確保できます。
char* buffer = new char[20];
でもこれはchar
とunsigned char
型の変数のサイズがどのコンパイラーでもちょうど 1 バイトなので、そうしているだけであって、上のコードを見ると、buffer
を実際に 20 バイトのメモリとして使いたいのか、それとも20個の文字が入る文字列として使いたいのか、型だけでは分からないです。
本来はchar
とunsigned char
は整数型なのですが、文字として使われる型でもあるので、使い道が色々ある型になっています。なので、メモリとして使う時も、文字としても数字としても使えてしまいます。要するに間違った使い方も簡単にできてしまいます。
前に紹介したように、こういう一般的な型より、専用の strong 型の方がお勧めです。そのため、特定のバイト数のメモリが使いたい場合のために、C++ 17 からバイト専用の型std::byte
が追加されました。
#include <cstddef>
std::byte* buffer = new std::byte[20];
↑のコードだと「20 バイトのメモリが欲しい」ってことはすぐ読み取れます。また、std::byte
にはキャスト関数以外、ビット計算用の演算子と比較演算子しか定義されていないため、うっかり間違った使い方をしてしまう恐れはないです。
buffer
の中身にアクセスする時は、std::byte
としてそのままアクセスするか、使いたい型へキャストしてからアクセスすることになります。
バイトを1つずつキャストする場合は、以下のように用意されているstd::to_integer<T>(std::byte)
という関数を使うのがお勧めです。
char first = std::to_integer<char>(buffer[0]);
int second = std::to_integer<int>(buffer[0]);
纏めてキャストしたい場合は、std::reinterpret_cast
を使いましょう。
char* buffers_as_char = reinterpret_cast<char*>(buffer);
char* buffer_as_int = reinterpret_cast<int*>(buffer);
昔から C++ を使っている人は、別に今まで通りchar
かunsigned char
でいいじゃんってなるかもしれないです。まあ、それもそうです。動作的にはあんまり違いはないですし、既存のchar
とunsigned char
を使っているコードをわざわざ変えたくないのも分かります。
でもこれから書く新しいコードを読みやすくて分かりやすくしたい人には、std::byte
を是非使ってみて欲しいです。
Discussion
ポインタ同士の変換について、
void*
との変換以外ではstatic_cast
ではなくreinterpret_cast
が必要になると思います。コメントありがとうございます。確かに
reinterpret_cast
とするべきですね。記事には反映しました。