コンテンツにスキップ

C++/標準ライブラリ/array

出典: フリー教科書『ウィキブックス(Wikibooks)』

<array> ヘッダー

[編集]

C++の標準ライブラリには、固定サイズの配列を扱うためのクラステンプレートstd::arrayが含まれています。この章では、std::arrayの基本的な使い方から、C++のバージョンによる進化、および実践的な使用例までを解説します。

イントロダクション

[編集]

<array>の概要

[編集]

<array>ヘッダーは、固定サイズの配列を表現するクラステンプレートstd::arrayを提供します。std::arrayは、C言語の配列に比べて安全で便利な機能を持っており、STL(標準テンプレートライブラリ)の他のコンテナと同様のインターフェースを提供します。

配列とstd::arrayの違い

[編集]

C言語の配列とstd::arrayの主な違いは以下の通りです:

  • std::arrayはSTLの一部であり、STLのアルゴリズムとシームレスに統合できます。
  • std::arrayも固定サイズであり、サイズを変更することはできません。
  • std::arrayもコンパイル時にサイズが決定され、ヒープではなくスタック上に配置されます。
  • std::arrayには、範囲チェックを行うメンバー関数at()があり、安全な要素アクセスが可能です。#

なぜstd::arrayを使用するのか

[編集]

std::arrayを使用する利点には以下の点が挙げられます:

安全性
範囲外アクセスに対するチェックが組み込まれているため、バグを減らすことができます。
可読性
STLの他のコンテナと一貫したインターフェースを持つため、コードの可読性が向上します。
パフォーマンス
固定サイズのため、メモリ割り当てのオーバーヘッドがなく、高速です。

歴史と変遷

[編集]

std::arrayの導入(C++11)

[編集]

std::arrayはC++11で導入されました。それ以前のC++には固定サイズ配列の標準的なクラスが存在せず、C言語の配列を使用する必要がありました。C++11でstd::arrayが導入されたことで、固定サイズ配列を安全に扱えるようになりました。

初期の機能と制限

[編集]

C++11のstd::arrayは、固定サイズの配列を表現するための基本的な機能を提供しましたが、いくつかの制限もありました。例えば、初期化リストを使用した初期化はサポートされていましたが、推論ガイドはありませんでした。

C++17以降の改善点

[編集]

C++17では、推論ガイドが導入され、std::arrayの初期化がさらに簡潔になりました。例えば、以下のようにautoを使用して配列を初期化できます:

auto ary = std::array{2, 3, 5, 7, 11};

このように、推論ガイドにより、テンプレート引数を明示的に指定することなくstd::arrayを初期化できるようになりました。

C++20でのさらなる改良点

[編集]

C++20では、std::arrayに対するさらなる改良が行われ、使い勝手が向上しました。例えば、コンパイル時の計算能力の向上や、より強力なコンパイル時チェックが追加されました。

基本的な使い方

[編集]

std::arrayの宣言と初期化

[編集]

std::arrayは、次のように宣言して初期化できます:

std::array<int, 5> arr1; // デフォルト初期化
std::array<int, 5> arr2 = {1, 2, 3, 4, 5}; // 初期化リストを使用
std::array<int, 5> arr3 = {}; // すべての要素を0で初期化
auto ary = std::array{2, 3, 5, 7, 11}; // C++17の推論ガイドによる初期化

これにより、固定サイズの配列が宣言され、適切に初期化されます。

メンバー関数の紹介

[編集]

基本的なメンバー関数

[編集]

std::arrayには、次のような基本的なメンバー関数があります:

size()
配列のサイズを返します。
max_size()
配列の最大サイズを返します。
empty()
配列が空であるかをチェックします。
#include <array>
#include <iostream>

auto main() -> int {
    std::array<int, 3> const arr = {10, 20, 30};
    std::cout << arr.size() << std::endl;                    // 3
    std::cout << arr.max_size() << std::endl;                // 3
    std::cout << std::boolalpha << arr.empty() << std::endl; // false
}

要素アクセス関数

[編集]

std::arrayでは、次の関数を使用して要素にアクセスできます:

operator[]
インデックスで要素にアクセスします。
at()
範囲チェックを行って要素にアクセスします。
front()
先頭要素にアクセスします。
back()
末尾要素にアクセスします。
std::array<int, 3> arr = {10, 20, 30};
int first = arr.front(); // 10
int second = arr[1]; // 20
int last = arr.back(); // 30

イテレーターの使用

[編集]

イテレーターの取得

[編集]

std::arrayはSTLのコンテナと同様に、イテレーターを提供します:

begin()
配列の先頭を指すイテレーターを返します。
end()
配列の終端の次を指すイテレーターを返します。
rbegin()
逆順の配列の先頭を指すイテレーターを返します。
rend()
逆順の配列の終端の次を指すイテレーターを返します。
for (auto it = arr.begin(); it != arr.end(); it++) {
    std::cout << *it << " ";
}
// 範囲ベースのforループ
for (const auto& element : arr) {
    std::cout << element << " ";
}

その他のメンバー関数

[編集]

fill()

[編集]

fill()は配列のすべての要素を指定した値で埋めます:

std::array<int, 5> arr;
arr.fill(5); // すべての要素を5で埋める

swap()

[編集]

swap()は2つの配列の内容を交換します:

std::array<int, 5> arr1 = {1, 2, 3, 4, 5};
std::array<int, 5> arr2 = {5, 4, 3, 2, 1};
arr1.swap(arr2); // arr1とarr2の内容を交換

アルゴリズムとの連携

[編集]

std::arrayは、STLのアルゴリズムとシームレスに連携できます。例えば、std::sortを使用して配列をソートすることができます:

std::array<int, 5> arr = {5, 3, 1, 4, 2};
std::sort(arr.begin(), arr.end()); // 配列をソート
for (const auto& elem : arr) {
    std::cout << elem << " "; // 1 2 3 4 5
}

ユーティリティ関数

[編集]

std::getを使用した要素アクセス

[編集]

std::getを使用して、インデックスで要素にアクセスできます:

std::array<int, 3> arr = {10, 20, 30};
int value = std::get<1>(arr); // 20

std::tuple_sizeとstd::tuple_elementの利用

[編集]

std::arrayはタプルと互換性があり、std::tuple_sizestd::tuple_elementを使用してサイズや要素型を取得できます:

constexpr std::size_t size = std::tuple_size<decltype(arr)>::value; // 3
using ElementType = std::tuple_element<1, decltype(arr)>::type; // int

std::arrayの利点と欠点

[編集]

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

[編集]

std::arrayは固定サイズのため、メモリ効率が高く、ヒープのメモリ割り当てが不要です。 他方、スタック上に確保されるため極端に大きなサイズを確保するとスタックオーバーフローの原因になります。

使いやすいインターフェース

[編集]

STLの他のコンテナと一貫したインターフェースを提供するため、使いやすく、コードの可読性が向上します。

可変サイズ配列(std::vector)との比較

[編集]

std::arrayは固定サイズであり、動的なサイズ変更が必要な場合にはstd::vectorの方が適しています。しかし、サイズが固定である場合は、std::arrayの方が効率的です。

実践例と応用

[編集]

std::arrayを使った基本的なアルゴリズム実装

[編集]

std::arrayを使用して、簡単なアルゴリズムを実装できます。例えば、要素の合計を計算する関数を作成できます:

std::array<int, 5> arr = {1, 2, 3, 4, 5};
int sum = std::accumulate(arr.begin(), arr.end(), 0); // 要素の合計を計算
std::cout << sum; // 15

多次元配列としての使用方法

[編集]

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

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& element : row) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
}

まとめと練習問題

[編集]

<array>ヘッダーの要点のまとめ

[編集]

<array>ヘッダーは、固定サイズの配列を安全かつ効率的に扱うためのクラステンプレートstd::arrayを提供します。std::arrayは、C++11以降の規格で導入され、C++17およびC++20でさらに改良されました。

練習問題

[編集]
  1. std::arrayを使って、配列の全要素を2倍にするプログラムを書いてください。
  2. std::arraystd::vectorを比較し、それぞれの利点と欠点について考察してください。
  3. 3x3の行列をstd::arrayを使って初期化し、その対角要素の合計を計算するプログラムを書いてください。

この章では、std::arrayの基本的な使い方から応用までを学びました。これにより、安全で効率的な固定サイズ配列の扱い方を理解できたはずです。