導入
C++で列挙型(enum class)を利用する際、デフォルトではint型が使用されます。しかし、保持する値が少なく、膨大な数のインスタンスを生成する場合や、ネットワーク通信のパケットサイズを極限まで小さくしたい場合、int(通常4バイト)を使用するのはメモリの無駄になることがあります。今回は、列挙型の「基底型」を明示的に指定することで、メモリ使用量を最適化する方法を解説します。
基礎知識
C++11から導入されたenum class(スコープ付き列挙型)は、名前空間の汚染を防ぐ優れた機能ですが、実は内部でどの整数型を使用するかを指定する「基底型指定(Underlying Type)」が可能です。これを指定しない場合、コンパイラはデフォルトでint型を選択します。uint8_tなどの小さな型を指定することで、列挙型のサイズを最小1バイトにまで抑えることが可能です。
実装/解決策
列挙型の定義時に、コロン(:)に続けてデータ型を指定するだけです。これにより、コンパイラはその列挙型のサイズを、指定したデータ型のサイズに合わせて最適化します。
例えば、フラグ管理などで0〜255の範囲しか使わないのであれば、intではなくuint8_tを指定することで、メモリ消費を4分の1に削減できます。
サンプルプログラム
以下のコードでは、通常のenum classと、基底型を指定したenum classのサイズを比較しています。
include
include
// 通常のenum class(デフォルトはint型、通常4バイト)
enum class DefaultEnum {
ValueA, ValueB
};
// 基底型を指定したenum class(uint8_tを指定し、1バイトに固定)
enum class CompactEnum : uint8_t {
ValueA, ValueB
};
int main() {
// それぞれのサイズをバイト単位で表示
std::cout << "デフォルトのサイズ: " << sizeof(DefaultEnum) << " バイト" << std::endl;
std::cout << "指定後のサイズ: " << sizeof(CompactEnum) << " バイト" << std::endl;
return 0;
}
応用・注意点
注意点として、指定した型が列挙する値の範囲をカバーしているか確認してください。例えば、uint8_tを指定したのに256以上の値を定義するとコンパイルエラーになります。また、メモリを節約できるとはいえ、CPUのアーキテクチャによっては、4バイト(int)単位でアクセスした方が高速な場合もあります。組み込み開発や、数百万個のオブジェクトを配列で持つようなメモリクリティカルな場面でこそ、その真価を発揮する手法です。むやみに全てのenumを小さくするのではなく、用途に合わせて適切に使い分けましょう。

コメント