【C++】STLのstd::arrayの使い方について詳しく解説

この記事では、C++の標準ライブラリに含まれるstd::arrayについて詳しく解説します。

std::arrayは、固定サイズの配列を効率的に扱うための便利なツールです。

この記事を読むことで、std::arrayの基本的な使い方や他の配列との違い、要素の操作方法、関数やSTLアルゴリズムとの連携方法などを学ぶことができます。

初心者の方でも理解しやすいように、具体的なコード例とともに説明していきますので、ぜひ最後までご覧ください。

目次から探す

std::arrayとは

std::arrayの概要

std::arrayは、C++標準ライブラリ(STL)の一部であり、固定サイズの配列を扱うためのコンテナです。

C++11で導入され、従来のC言語の配列に比べて多くの利点を持っています。

std::arrayは、テンプレートクラスであり、型とサイズをテンプレートパラメータとして受け取ります。

これにより、コンパイル時にサイズが決定され、メモリ効率が向上します。

std::arrayとC++の他の配列との違い

C言語の配列との比較

C言語の配列は、固定サイズの配列を簡単に宣言できる一方で、いくつかの制約があります。

例えば、配列のサイズはコンパイル時に決定され、動的に変更することはできません。

また、配列のサイズを取得するための標準的な方法がなく、ポインタ演算を多用する必要があります。

一方、std::arrayは以下の利点を持っています:

  • サイズの取得が簡単size()メソッドを使って配列のサイズを簡単に取得できます。
  • 範囲チェックat()メソッドを使うことで、範囲外アクセスを防ぐことができます。
  • STLとの互換性std::arrayはSTLの他のコンテナと同様に扱うことができ、STLアルゴリズムと組み合わせて使用できます。

以下に、C言語の配列とstd::arrayの基本的な使い方の違いを示します。

#include <iostream>
#include <array>
int main() {
    // C言語の配列
    int c_array[5] = {1, 2, 3, 4, 5};
    std::cout << "C言語の配列のサイズ: " << sizeof(c_array) / sizeof(c_array[0]) << std::endl;
    // std::array
    std::array<int, 5> cpp_array = {1, 2, 3, 4, 5};
    std::cout << "std::arrayのサイズ: " << cpp_array.size() << std::endl;
    return 0;
}

std::vectorとの比較

std::vectorは、動的にサイズを変更できる配列コンテナであり、非常に柔軟です。

std::vectorは、要素の追加や削除が頻繁に行われる場合に適しています。

しかし、std::arrayには以下の利点があります:

  • メモリ効率std::arrayは固定サイズであるため、メモリ効率が高くなります。
  • コンパイル時のサイズチェックstd::arrayのサイズはコンパイル時に決定されるため、サイズに関するエラーを早期に検出できます。
  • パフォーマンスstd::arrayは固定サイズであるため、動的メモリ割り当てが不要であり、パフォーマンスが向上します。

以下に、std::arraystd::vectorの基本的な使い方の違いを示します。

#include <iostream>
#include <array>
#include <vector>
int main() {
    // std::array
    std::array<int, 5> cpp_array = {1, 2, 3, 4, 5};
    std::cout << "std::arrayのサイズ: " << cpp_array.size() << std::endl;
    // std::vector
    std::vector<int> cpp_vector = {1, 2, 3, 4, 5};
    std::cout << "std::vectorのサイズ: " << cpp_vector.size() << std::endl;
    // std::vectorに要素を追加
    cpp_vector.push_back(6);
    std::cout << "std::vectorのサイズ(要素追加後): " << cpp_vector.size() << std::endl;
    return 0;
}

このように、std::arraystd::vectorはそれぞれ異なる用途に適しており、使い分けることで効率的なプログラムを作成することができます。

std::arrayの基本的な使い方

std::arrayの宣言と初期化

基本的な宣言方法

std::arrayはテンプレートクラスであり、型とサイズを指定して宣言します。

以下は基本的な宣言方法の例です。

#include <array>
#include <iostream>
int main() {
    std::array<int, 5> arr; // int型の要素を5つ持つstd::arrayを宣言
    return 0;
}

初期化リストを使った初期化

std::arrayは初期化リストを使って初期化することができます。

以下はその例です。

#include <array>
#include <iostream>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5}; // 初期化リストを使って初期化
    for (int i : arr) {
        std::cout << i << " ";
    }
    return 0;
}

このコードを実行すると、配列の要素が順に出力されます。

デフォルト初期化

std::arrayはデフォルト初期化もサポートしています。

デフォルト初期化では、要素は型に応じたデフォルト値で初期化されます。

#include <array>
#include <iostream>
int main() {
    std::array<int, 5> arr = {}; // デフォルト初期化
    for (int i : arr) {
        std::cout << i << " "; // すべての要素が0で初期化される
    }
    return 0;
}

要素へのアクセス方法

インデックスを使ったアクセス

std::arrayの要素にはインデックスを使ってアクセスできます。

これはC言語の配列と同じ方法です。

#include <array>
#include <iostream>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    std::cout << arr[2] << std::endl; // インデックス2の要素にアクセス
    return 0;
}

at()メソッドを使ったアクセス

at()メソッドを使うと、範囲外アクセス時に例外を投げるため、安全に要素にアクセスできます。

#include <array>
#include <iostream>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    try {
        std::cout << arr.at(2) << std::endl; // インデックス2の要素にアクセス
        std::cout << arr.at(5) << std::endl; // 範囲外アクセスで例外が発生
    } catch (const std::out_of_range& e) {
        std::cerr << "範囲外アクセス: " << e.what() << std::endl;
    }
    return 0;
}

front()とback()メソッド

front()メソッドは最初の要素、back()メソッドは最後の要素にアクセスします。

#include <array>
#include <iostream>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    std::cout << "最初の要素: " << arr.front() << std::endl;
    std::cout << "最後の要素: " << arr.back() << std::endl;
    return 0;
}

サイズの取得

size()メソッド

size()メソッドを使うと、配列のサイズを取得できます。

#include <array>
#include <iostream>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    std::cout << "配列のサイズ: " << arr.size() << std::endl;
    return 0;
}

max_size()メソッド

max_size()メソッドは、配列が持つことのできる最大の要素数を返します。

std::arrayの場合、size()と同じ値を返します。

#include <array>
#include <iostream>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    std::cout << "配列の最大サイズ: " << arr.max_size() << std::endl;
    return 0;
}

以上が、std::arrayの基本的な使い方に関する解説です。

次のセクションでは、std::arrayの操作について詳しく見ていきます。

std::arrayの操作

要素の変更

インデックスを使った変更

std::arrayの要素を変更する最も基本的な方法は、インデックスを使うことです。

C言語の配列と同様に、インデックスを指定して要素にアクセスし、その値を変更することができます。

#include <iostream>
#include <array>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    // インデックスを使って要素を変更
    arr[2] = 10;
    // 変更後の配列を表示
    for (int i = 0; i < arr.size(); ++i) {
        std::cout << arr[i] << " ";
    }
    return 0;
}

このコードを実行すると、配列の3番目の要素が10に変更され、出力は以下のようになります。

1 2 10 4 5

fill()メソッドを使った一括変更

std::arrayには、全ての要素を同じ値で一括変更するためのfill()メソッドがあります。

これを使うと、配列全体を簡単に初期化することができます。

#include <iostream>
#include <array>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    // fill()メソッドを使って全ての要素を0に変更
    arr.fill(0);
    // 変更後の配列を表示
    for (int i = 0; i < arr.size(); ++i) {
        std::cout << arr[i] << " ";
    }
    return 0;
}

このコードを実行すると、配列の全ての要素が0に変更され、出力は以下のようになります。

0 0 0 0 0

配列のコピーとスワップ

コピーの方法

std::arrayはコピー操作が簡単に行えます。

代入演算子を使って、別のstd::arrayにコピーすることができます。

#include <iostream>
#include <array>
int main() {
    std::array<int, 5> arr1 = {1, 2, 3, 4, 5};
    std::array<int, 5> arr2;
    // 配列のコピー
    arr2 = arr1;
    // コピー後の配列を表示
    for (int i = 0; i < arr2.size(); ++i) {
        std::cout << arr2[i] << " ";
    }
    return 0;
}

このコードを実行すると、arr1の内容がarr2にコピーされ、出力は以下のようになります。

1 2 3 4 5

swap()メソッド

std::arrayには、2つの配列の内容を交換するためのswap()メソッドも用意されています。

これを使うと、簡単に配列の内容を入れ替えることができます。

#include <iostream>
#include <array>
int main() {
    std::array<int, 5> arr1 = {1, 2, 3, 4, 5};
    std::array<int, 5> arr2 = {6, 7, 8, 9, 10};
    // 配列のスワップ
    arr1.swap(arr2);
    // スワップ後の配列を表示
    std::cout << "arr1: ";
    for (int i = 0; i < arr1.size(); ++i) {
        std::cout << arr1[i] << " ";
    }
    std::cout << "\narr2: ";
    for (int i = 0; i < arr2.size(); ++i) {
        std::cout << arr2[i] << " ";
    }
    return 0;
}

このコードを実行すると、arr1とarr2の内容が入れ替わり、出力は以下のようになります。

arr1: 6 7 8 9 10 
arr2: 1 2 3 4 5

イテレーション

begin()とend()メソッド

std::arrayはSTLの他のコンテナと同様に、イテレータを使って要素を順に処理することができます。

begin()メソッドend()メソッドを使って、配列の先頭と末尾を示すイテレータを取得できます。

#include <iostream>
#include <array>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    // イテレータを使って配列の要素を表示
    for (auto it = arr.begin(); it != arr.end(); ++it) {
        std::cout << *it << " ";
    }
    return 0;
}

このコードを実行すると、配列の全ての要素が順に表示され、出力は以下のようになります。

1 2 3 4 5

range-based forループ

C++11以降では、range-based forループを使って、より簡潔に配列の要素を処理することができます。

#include <iostream>
#include <array>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    // range-based forループを使って配列の要素を表示
    for (const auto& elem : arr) {
        std::cout << elem << " ";
    }
    return 0;
}

このコードを実行すると、配列の全ての要素が順に表示され、出力は以下のようになります。

1 2 3 4 5

range-based forループを使うことで、コードがより読みやすく、簡潔になります。

std::arrayの応用

多次元配列としてのstd::array

二次元配列の宣言と初期化

std::arrayは多次元配列としても利用できます。

例えば、2次元配列を宣言する場合、std::arrayをネストして使用します。

#include <array>
#include <iostream>
int main() {
    // 3x3の二次元配列を宣言
    std::array<std::array<int, 3>, 3> matrix = {{
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    }};
    // 配列の内容を表示
    for (const auto& row : matrix) {
        for (const auto& elem : row) {
            std::cout << elem << " ";
        }
        std::cout << std::endl;
    }
    return 0;
}

このコードでは、3×3の二次元配列を宣言し、初期化リストを使って初期化しています。

多次元配列の操作

多次元配列の要素にアクセスするには、インデックスを2回使用します。

#include <array>
#include <iostream>
int main() {
    std::array<std::array<int, 3>, 3> matrix = {{
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    }};
    // 要素の変更
    matrix[1][1] = 10;
    // 配列の内容を表示
    for (const auto& row : matrix) {
        for (const auto& elem : row) {
            std::cout << elem << " ";
        }
        std::cout << std::endl;
    }
    return 0;
}

この例では、matrix[1][1]の要素を10に変更しています。

std::arrayと関数

std::arrayを引数に取る関数

std::arrayを関数の引数として渡すことができます。

以下の例では、std::arrayを引数に取る関数を定義しています。

#include <array>
#include <iostream>
// std::arrayを引数に取る関数
void printArray(const std::array<int, 5>& arr) {
    for (const auto& elem : arr) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
}
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    printArray(arr);
    return 0;
}

この関数は、std::arrayの内容を表示します。

std::arrayを返す関数

std::arrayを返す関数も定義できます。

以下の例では、std::arrayを返す関数を定義しています。

#include <array>
#include <iostream>
// std::arrayを返す関数
std::array<int, 5> createArray() {
    return {1, 2, 3, 4, 5};
}
int main() {
    std::array<int, 5> arr = createArray();
    for (const auto& elem : arr) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
    return 0;
}

この関数は、初期化されたstd::arrayを返します。

std::arrayとSTLアルゴリズム

std::sort()を使ったソート

std::arrayはSTLのアルゴリズムと一緒に使用できます。

以下の例では、std::sort()を使ってstd::arrayをソートしています。

#include <array>
#include <algorithm>
#include <iostream>
int main() {
    std::array<int, 5> arr = {5, 3, 4, 1, 2};
    // std::sort()を使ってソート
    std::sort(arr.begin(), arr.end());
    // ソート後の配列を表示
    for (const auto& elem : arr) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
    return 0;
}

このコードでは、std::sort()を使って配列を昇順にソートしています。

std::find()を使った検索

std::find()を使ってstd::array内の要素を検索することもできます。

#include <array>
#include <algorithm>
#include <iostream>
int main() {
    std::array<int, 5> arr = {5, 3, 4, 1, 2};
    // std::find()を使って要素を検索
    auto it = std::find(arr.begin(), arr.end(), 3);
    if (it != arr.end()) {
        std::cout << "Element found at index: " << std::distance(arr.begin(), it) << std::endl;
    } else {
        std::cout << "Element not found" << std::endl;
    }
    return 0;
}

このコードでは、std::find()を使って配列内の要素3を検索し、そのインデックスを表示しています。

要素が見つからない場合は Element not found と表示されます。

std::arrayの利点と制限

std::arrayの利点

固定サイズによるメモリ効率

std::arrayの最大の利点の一つは、その固定サイズによるメモリ効率の良さです。

std::arrayはコンパイル時にサイズが決定されるため、動的メモリ割り当てが不要です。

これにより、メモリの断片化を防ぎ、メモリ使用量を最適化することができます。

例えば、以下のコードでは、std::arrayを使って固定サイズの配列を宣言しています。

#include <iostream>
#include <array>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    for (int i : arr) {
        std::cout << i << " ";
    }
    return 0;
}

このコードでは、std::arrayが固定サイズであるため、メモリの効率的な使用が可能です。

コンパイル時のサイズチェック

std::arrayのもう一つの利点は、コンパイル時にサイズがチェックされることです。

これにより、配列のサイズに関するエラーを早期に検出することができます。

例えば、以下のコードでは、配列のサイズが不一致であるため、コンパイルエラーが発生します。

#include <array>
int main() {
    std::array<int, 5> arr = {1, 2, 3, 4}; // サイズが不一致
    return 0;
}

このように、std::arrayを使用することで、配列のサイズに関するエラーを防ぐことができます。

std::arrayの制限

サイズの固定

std::arrayの最大の制限は、そのサイズが固定されていることです。

一度宣言されたstd::arrayのサイズは変更できません。

これは、動的にサイズを変更する必要がある場合には不便です。

例えば、ユーザーからの入力に応じて配列のサイズを変更する場合には、std::vectorの方が適しています。

#include <vector>
#include <iostream>
int main() {
    int n;
    std::cout << "Enter the size of the array: ";
    std::cin >> n;
    std::vector<int> vec(n); // 動的にサイズを変更可能
    return 0;
}

このように、動的なサイズ変更が必要な場合には、std::vectorを使用する方が適しています。

動的メモリ管理ができない

std::arrayは固定サイズであるため、動的メモリ管理ができません。

これは、動的にメモリを割り当てたり解放したりする必要がある場合には不便です。

例えば、大量のデータを扱う場合や、メモリ使用量を最適化する必要がある場合には、std::vectorや他の動的コンテナを使用する方が適しています。

#include <vector>
#include <iostream>
int main() {
    std::vector<int> vec;
    for (int i = 0; i < 100; ++i) {
        vec.push_back(i); // 動的にメモリを割り当て
    }
    return 0;
}

このように、動的メモリ管理が必要な場合には、std::vectorを使用する方が適しています。

std::arrayは固定サイズの配列を効率的に扱うための便利なコンテナです。

固定サイズによるメモリ効率の良さや、コンパイル時のサイズチェックといった利点がありますが、サイズの固定や動的メモリ管理ができないといった制限もあります。

用途に応じて、std::arrayと他のコンテナを使い分けることが重要です。

まとめ

この記事では、C++のSTL(Standard Template Library)に含まれるstd::arrayについて詳しく解説しました。

std::arrayは、固定サイズの配列を効率的に扱うための強力なツールです。

この記事を通じて、std::arrayの基本的な使い方から応用までを理解し、実際のプログラミングに役立てていただければ幸いです。

当サイトはリンクフリーです。出典元を明記していただければ、ご自由に引用していただいて構いません。

目次から探す