世の中には様々な理由で生配列を直接使う場合があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <iostream> int main() { // 東海道線 const char* tokaido[] = { "Tokyo", // 東京 "Shinagawa", // 品川 "Kawasaki", // 川崎 "Yokohama", // 横浜 "Oofuna", // 大船 }; const int array_size = 5; // 要素数 // 出力 for (int i = 0; i < array_size; ++i) { std::cout << tokaido[i] << std::endl; } return 0; } |
要素数が変わったらarray_sizeの数値も忘れずに変更しなければいけませんが、必ず忘れることでしょう。
配列の要素は静的に決定するので計算で求めることができます。
C言語の時代から人類は500万回以上も配列の要素数取得マクロを再発明してきました。大体、どんなプロジェクトを覗いても配列サイズ取得のマクロを用意してあることが多かったです。
実際、どれほど使われていたかは定かではありませんが……。
1 |
#define GET_ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) |
全体のサイズを1要素のサイズで割ることで配列の要素数を計算できます。
これを使えば要素数が増えた時でも自動的に値が更新されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <iostream> #define GET_ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) int main() { // 東海道線 const char* tokaido[] = { "Tokyo", // 東京 "Shinagawa", // 品川 "Kawasaki", // 川崎 "Yokohama", // 横浜 "Oofuna", // 大船 }; const int array_size = GET_ARRAY_SIZE(tokaido); // 要素数 // 出力 for (int i = 0; i < array_size; ++i) { std::cout << tokaido[i] << std::endl; } return 0; } |
ただマクロでは名前空間の指定ができません。
C++的にはテンプレートで書くのがいいでしょう。
1 2 3 4 |
template <typename Array, int N> constexpr int arraySize1D( Array (&)[N] ) { return N; } |
関数なので任意の名前空間に閉じ込められます。
ちょっと応用すれば2次元配列の要素も簡単に一発で取得できます。
1 2 3 4 5 |
template <typename Array, int N, int M> void arraySize2D(Array (&)[N][M], int* x, int* y) { *x = M; *y = N; } |
ただし配列を引数で受け取った先で取得したい場合など、コンパイラが要素数を把握できない状況では これらの取得方法は使えません。
結局、生配列を取り回し良く使うには、先頭アドレスと要素数とのペアとして管理する必要が出てきます。
C++の恩恵を最大限に活用する為にもコンテナクラスを使いましょう。
まとめ
- 生配列の要素数を取得する方法を知ろう
- 生配列の要素数が取得できないシチュエーションを知ろう
- 教義を曲げてでもコンテナクラスを使おう