C++で学ぶ可変長配列!初心者から上級者までの5つのサンプルで完全理解

C++プログラミングの可変長配列を学ぶためのイラストC++
この記事は約16分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

プログラミングでは、データを効率的に管理するために様々なデータ構造が使われています。

C++言語を学ぶ上で、可変長配列は非常に重要な概念の一つです。

この記事では、C++における可変長配列の基本から、その利点、使い方に至るまでを初心者でも理解できるように詳細に解説していきます。

C++における可変長配列を理解し、実際にコードを書くことで、プログラミングスキルを一層深めることができるでしょう。

●C++における可変長配列とは

C++において、可変長配列とは、そのサイズを動的に変更できる配列のことを指します。

通常の配列では、そのサイズは宣言時に固定され、後から変更することはできません。

しかし、可変長配列を使用することで、プログラム実行中に配列のサイズを拡張したり縮小したりすることが可能になります。

これにより、より柔軟なデータ構造をプログラム内で扱うことができるようになります。

C++には、このような可変長配列を扱うための標準ライブラリとして、std::vectorが提供されています。

○可変長配列の基本概念

可変長配列を理解するためには、まず「配列」という概念を理解する必要があります。

配列とは、同じ型のデータを一列に並べたデータ構造です。

C++では、固定長の配列を宣言する際には、そのサイズを明示的に指定します。

しかし、プログラム実行時にデータの量が変動する場合、固定長の配列では対応できません。

ここで可変長配列が役立ちます。

可変長配列では、必要に応じて配列のサイズを動的に変更できるため、プログラムがより柔軟にデータを扱うことが可能になります。

○C++における可変長配列の利点

C++での可変長配列の使用にはいくつかの利点があります。

まず、メモリの効率的な利用が挙げられます。

固定長の配列では、必要以上のメモリを確保することがありますが、可変長配列では使用するデータの量に応じてメモリを確保するため、メモリの無駄が少なくなります。

また、データの追加や削除が容易であることも大きな利点です。

配列の終端に新しい要素を追加したり、特定の要素を削除したりする操作が、std::vectorを用いることで簡単に行えます。

さらに、C++の標準ライブラリに組み込まれているため、安全性と移植性に優れているという点も重要です。

これらの利点により、可変長配列はC++プログラミングにおいて広く使われています。

●可変長配列の基本的な作り方

C++における可変長配列の作り方を学ぶことは、プログラミングスキルを高める上で非常に重要です。

基本的には、std::vectorという標準ライブラリを使用します。

これは、動的にサイズが変更できる配列であり、様々な操作が可能です。

例えば、配列のサイズを指定する、要素を追加する、特定の位置の要素にアクセスするなどの操作が簡単に行えます。

ここでは、まず基本的な可変長配列の宣言と初期化の方法について解説し、次に要素の追加とアクセスの方法を解説します。

○サンプルコード1:基本的な可変長配列の宣言と初期化

C++で可変長配列を宣言する基本的な方法は、std::vector型を使用することです。

下記のサンプルコードは、int型の可変長配列を宣言し、いくつかの要素で初期化する方法を表しています。

#include <iostream>
#include <vector>

int main() {
    // int型の可変長配列を宣言し、初期化する
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // 配列の内容を表示する
    for (int number : numbers) {
        std::cout << number << " ";
    }

    return 0;
}

このコードでは、std::vector<int>型を使って整数の配列numbersを宣言し、初期値{1, 2, 3, 4, 5}で初期化しています。

for文を使って配列の各要素を順に出力しています。

○サンプルコード2:要素の追加とアクセス

可変長配列に新しい要素を追加するには、push_backメソッドを使用します。

また、特定の要素にアクセスするには、配列のインデックスを指定します。

下記のサンプルコードでは、配列に新しい要素を追加し、特定の要素にアクセスする方法を表しています。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers;

    // 要素を追加する
    numbers.push_back(10);
    numbers.push_back(20);
    numbers.push_back(30);

    // 2番目の要素にアクセスする
    std::cout << "2番目の要素: " << numbers[1] << std::endl;

    // 配列の内容を表示する
    for (int number : numbers) {
        std::cout << number << " ";
    }

    return 0;
}

このコードでは、まず空のstd::vector<int>型配列numbersを宣言しています。

その後、push_backメソッドを使って配列に3つの整数を追加し、numbers[1]を使用して2番目の要素にアクセスしています。

最後に、配列の内容を全て出力しています。

●可変長配列の詳細な使い方

C++での可変長配列の使い方を理解するには、さまざまな操作を習得することが重要です。

ここでは、特にサイズの調整とメモリ管理、反復処理、アルゴリズムの適用に焦点を当てて解説します。

これらの操作を理解し、使いこなせるようになることで、C++の可変長配列をより効果的に活用できるようになります。

○サンプルコード3:サイズの調整とメモリ管理

C++のstd::vectorでは、配列のサイズを動的に調整することができます。

また、不要になったメモリは適切に解放することが重要です。

下記のサンプルコードでは、サイズの調整とメモリの解放について説明しています。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers;

    // 要素を追加する
    for (int i = 1; i <= 5; ++i) {
        numbers.push_back(i);
    }

    // サイズを表示
    std::cout << "サイズ: " << numbers.size() << std::endl;

    // サイズを変更する
    numbers.resize(3);

    // 変更後のサイズと要素を表示
    std::cout << "変更後のサイズ: " << numbers.size() << std::endl;
    for (int number : numbers) {
        std::cout << number << " ";
    }
    std::cout << std::endl;

    // メモリを解放する
    numbers.clear();
    numbers.shrink_to_fit();

    // メモリ解放後のサイズを表示
    std::cout << "メモリ解放後のサイズ: " << numbers.size() << std::endl;

    return 0;
}

このコードでは、まず5つの要素を配列に追加し、その後、resizeメソッドを使って配列のサイズを3に変更しています。

最後に、clearshrink_to_fitを使って配列の中身をクリアし、メモリを解放しています。

○サンプルコード4:反復処理とアルゴリズムの適用

C++の可変長配列を使うと、様々なアルゴリズムや反復処理を簡単に実装できます。

下記のサンプルコードでは、反復処理とアルゴリズムの適用方法を表しています。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {4, 2, 3, 1, 5};

    // 配列の要素を昇順にソートする
    std::sort(numbers.begin(), numbers.end());

    // ソート後の配列を表示する
    std::cout << "ソート後: ";
    for (int number : numbers) {
        std::cout << number << " ";
    }
    std::cout << std::endl;

    // 条件に合う要素を見つける
    auto it = std::find(numbers.begin(), numbers.end(), 3);
    if (it != numbers.end()) {
        std::cout << "要素3が見つかりました: " << *it << std::endl;
    } else {
        std::cout << "要素3は見つかりませんでした。" << std::endl;
    }

    return 0;
}

このコードでは、std::sortを使って配列を昇順にソートし、std::findを使って特定の要素を検索しています。

これらの関数は、C++の標準ライブラリに含まれる強力なツールで、効率的なプログラミングを可能にします。

●可変長配列の応用例

C++の可変長配列は多岐にわたる応用が可能で、プログラミングの幅を広げる重要な要素です。

ここでは、データ構造のカスタマイズと効率的なデータ処理という2つの重要な応用例を取り上げ、具体的なサンプルコードと共に詳細に解説します。

これらの応用例を理解し活用することで、C++プログラミングにおける可変長配列の真価を引き出すことができます。

○サンプルコード5:データ構造のカスタマイズ

C++のstd::vectorを使用することで、様々なデータ構造をカスタマイズしやすくなります。

例えば、複数のデータ型を含む構造体やクラスを配列に格納することで、複雑なデータ構造を効率的に扱うことができます。

#include <iostream>
#include <vector>
#include <string>

// ユーザー情報を格納する構造体
struct User {
    std::string name;
    int age;
};

int main() {
    // User構造体の可変長配列を作成
    std::vector<User> users = {
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35}
    };

    // 各ユーザーの情報を表示
    for (const auto& user : users) {
        std::cout << "Name: " << user.name << ", Age: " << user.age << std::endl;
    }

    return 0;
}

このコードでは、Userという構造体を定義し、それを要素とするstd::vectorを使用しています。

各要素にユーザーの名前と年齢を格納し、それらの情報を出力しています。

○サンプルコード6:効率的なデータ処理

可変長配列を用いることで、データ処理をより効率的に行うことができます。

特に、大量のデータに対する処理や、データの動的な追加・削除が必要な場合にその力を発揮します。

下記のサンプルコードでは、データの集計処理の例を表しています。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> data = {10, 20, 30, 40, 50};

    // データの合計値を計算する
    int sum = 0;
    for (int value : data) {
        sum += value;
    }

    std::cout << "合計: " << sum << std::endl;

    // 平均値を計算する
    double average = static_cast<double>(sum) / data.size();
    std::cout << "平均: " << average << std::endl;

    return 0;
}

このコードでは、整数の配列を作成し、その合計値と平均値を計算しています。

●注意点と対処法

C++における可変長配列の使用には多くの利点がありますが、注意すべき点もいくつか存在します。

特にパフォーマンスの問題やメモリリークは、効果的なプログラミングの障害となり得るため、これらの問題を理解し、適切に対処することが重要です。

ここでは、これらの問題に対する対処法を詳細に解説します。

○パフォーマンスの問題

C++のstd::vectorを使用する際には、パフォーマンスに影響を与える要因として、要素の追加や削除、メモリの確保と解放があります。

特に、大量のデータを扱う場合や、頻繁にサイズを変更する場合には、これらの操作がパフォーマンスに影響を与える可能性があります。

対処法としては、事前に必要なサイズを予測してreserveメソッドを使用し、必要なメモリをあらかじめ確保しておくことが有効です。

これにより、追加操作時のメモリ再確保のオーバーヘッドを減らすことができます。

また、要素の追加や削除が頻繁に発生する場合は、std::liststd::dequeなど、他のコンテナの使用を検討することも一つの方法です。

○メモリリークの防止

C++では、動的に確保したメモリの管理が不適切であるとメモリリークを引き起こす可能性があります。

std::vectorを使用する場合、通常はスコープの終了時に自動的にメモリが解放されますが、例外が発生した場合など、特定の状況では意図しないメモリリークが発生することがあります。

メモリリークを防ぐためには、例外安全なプログラミングを心がけることが重要です。

具体的には、リソースの確保と解放をstd::vectorなどのRAII(Resource Acquisition Is Initialization)に準拠したクラスに任せることで、例外が発生してもリソースが適切に解放されるようにします。

また、プログラムの各部分でメモリの使用状況を適切に監視し、不要になったメモリは積極的に解放することも、メモリリークを防ぐ上で有効な手段です。

●可変長配列のカスタマイズ方法

C++の可変長配列、特にstd::vectorは高度にカスタマイズ可能で、様々な用途に応じて拡張することができます。

ここでは、独自の機能を追加した可変長配列の作成方法と、外部ライブラリを利用した高度なデータ構造の利用方法について解説します。

これらのカスタマイズ方法を理解することで、C++プログラミングの柔軟性と効率性をさらに高めることができます。

○サンプルコード7:独自の機能を追加した可変長配列

C++では、クラスを定義することでstd::vectorに独自の機能を追加できます。

#include <iostream>
#include <vector>
#include <numeric>

template <typename T>
class StatsVector : public std::vector<T> {
public:
    T getSum() const {
        return std::accumulate(this->begin(), this->end(), T(0));
    }

    double getAverage() const {
        if (this->empty()) return 0.0;
        return static_cast<double>(getSum()) / this->size();
    }
};

int main() {
    StatsVector<int> numbers = {1, 2, 3, 4, 5};

    std::cout << "合計: " << numbers.getSum() << std::endl;
    std::cout << "平均: " << numbers.getAverage() << std::endl;

    return 0;
}

このコードでは、StatsVectorという新しいクラスを定義し、std::vectorを継承しています。

getSumgetAverageメソッドを追加し、配列の合計値と平均値を計算できるようにしています。

○サンプルコード8:ライブラリの利用

C++でのプログラミングでは、様々な外部ライブラリを利用して、可変長配列の機能を拡張することができます。

ここでは、Boostライブラリの一部であるboost::multi_arrayを使用した多次元配列の例を紹介します。

#include <iostream>
#include <boost/multi_array.hpp>
#include <cassert>

int main() {
    // 3x3の2次元配列を作成
    boost::multi_array<int, 2> matrix(boost::extents[3][3]);

    // 配列に値を設定
    int value = 0;
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            matrix[i][j] = ++value;
        }
    }

    // 配列の内容を表示
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            std::cout << matrix[i][j] << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

このコードでは、Boostライブラリのboost::multi_arrayを使用して2次元配列を作成し、操作しています。

BoostライブラリはC++の標準ライブラリを補完する形で多くの追加機能を提供し、可変長配列をはじめとするデータ構造の機能を拡張する上で非常に便利です。

まとめ

本記事では、C++における可変長配列の基本から応用までを詳細に解説しました。

基本的な宣言と初期化、要素の追加とアクセス、サイズ調整やメモリ管理、さらにはデータ構造のカスタマイズやライブラリの利用に至るまで、実用的なサンプルコードを交えて説明しました。

これらの知識と技術を駆使することで、読者はC++における可変長配列をより深く理解し、効率的に利用することが可能になるでしょう。