C++: STL コンテナ

これまで、特定の型の関数・クラスを書くテンプレートを学びました。

でも実際のプロジェクトでは、コンテナ(動的配列、連結リスト)を自分で書くのは大変。

C++標準ライブラリのテンプレート(STL)は既製のコンテナを提供、すぐに使える!


1. STL とは?

STL(Standard Template Library、標準テンプレートライブラリ)は C++ 標準ライブラリの中核:

構成要素 役割
コンテナ データを格納 std::vectorstd::array
イテレータ コンテナの要素にアクセス begin()end()
アルゴリズム データを操作 std::sortstd::find
関数オブジェクト 関数を定義 std::lessstd::greater
💡 ヒント: STL はテンプレートで実装、どの型でも使える。



2. vector(最もよく使う)

(1) 2.1 vector とは?

std::vector動的配列 —— 要素を追加・削除すると自動的にサイズが変わる。

特徴 配列 vector
サイズ変更 不可 可(動的)
メモリ スタックまたはヒープ ヒープ
アクセス arr[i] vec[i] または vec.at(i)
使いやすさ ⭐⭐ ⭐⭐⭐⭐⭐

▶ サンプル 1:vector の基本的な使い方(難易度 ⭐)

CPP
#include <iostream>
#include <vector>

int main() {
    // int の vector
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    // 要素へのアクセス
    std::cout << "最初の要素:" << vec[0] << std::endl;
    std::cout << "2番目の要素:" << vec.at(1) << std::endl;
    
    // 要素の変更
    vec[0] = 100;
    
    // サイズの取得
    std::cout << "サイズ:" << vec.size() << std::endl;
    
    return 0;
}
▶ 試してみよう
💡 ヒント: vec.at(i)境界チェックし、範囲外なら例外を投げる;vec[i] はチェックなし、高速。


(2) 2.2 追加と削除

CPP
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec;
    
    // 末尾に追加
    vec.push_back(10);
    vec.push_back(20);
    vec.push_back(30);
    
    // 末尾を削除
    vec.pop_back();
    
    // 中間に挿入
    vec.insert(vec.begin() + 1, 15); // 位置1に15を挿入
    
    // 中間を削除
    vec.erase(vec.begin() + 1); // 位置1を削除
    
    return 0;
}

(3) 2.3 vector の走査

方法1:インデックス(昔ながらの方法)

CPP
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    for (size_t i = 0; i < vec.size(); i++) {
        std::cout << vec[i] << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

方法2:範囲for文(C++11以降、推奨)

CPP
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    for (int x : vec) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

方法3:イテレータ(一番柔軟)

CPP
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    return 0;
}
💡 推奨: 読み取りだけなら範囲for文(C++11以降)、一番簡潔。



3. array(固定サイズ配列)

(1) 3.1 array とは?

std::array固定サイズの配列、でも従来の配列より使いやすい。

特徴 従来の配列 array
サイズ取得 不可 可(size() で)
ポインタへの変換 自動 明示的
使いやすさ ⭐⭐ ⭐⭐⭐⭐

▶ サンプル 2:array の基本的な使い方(難易度 ⭐)

CPP
#include <iostream>
#include <array>

int main() {
    // 5個の int の array
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    
    // 要素へのアクセス
    std::cout << "最初の要素:" << arr[0] << std::endl;
    
    // サイズの取得
    std::cout << "サイズ:" << arr.size() << std::endl;
    
    return 0;
}
▶ 試してみよう
💡 ヒント: std::array のサイズはコンパイル時に決定、動的に変えられない。



4. deque(両端キュー)

(1) 4.1 deque とは?

std::deque両端キュー —— 先頭と末尾の両方で高速に追加・削除。

操作 vector deque
末尾追加 O(1) O(1)
先頭追加 O(n) O(1)
ランダムアクセス O(1) O(1)

▶ サンプル 3:deque の基本的な使い方(難易度 ⭐⭐)

CPP
#include <iostream>
#include <deque>

int main() {
    std::deque<int> dq;
    
    // 末尾に追加
    dq.push_back(10);
    dq.push_back(20);
    
    // 先頭に追加
    dq.push_front(5);
    dq.push_front(1);
    
    // dqの内容:1, 5, 10, 20
    
    for (int x : dq) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    return 0;
}
▶ 試してみよう

5. list(連結リスト)

(1) 5.1 list とは?

std::list連結リスト —— 各要素が次の要素のアドレスを持つ。

操作 vector list
ランダムアクセス O(1) ❌ 不可
挿入・削除 O(n) O(1)
メモリ使用 連続 追加(ポインタ)

▶ サンプル 4:list の基本的な使い方(難易度 ⭐⭐)

CPP
#include <iostream>
#include <list>

int main() {
    std::list<int> lst = {1, 2, 3, 4, 5};
    
    // 先頭に追加
    lst.push_front(0);
    
    // 末尾に追加
    lst.push_back(6);
    
    // 値で削除(3を削除)
    lst.remove(3);
    
    for (int x : lst) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    
    return 0;
}
▶ 試してみよう

6. forward_list(片方向連結リスト)

(1) 6.1 forward_list とは?

std::forward_list片方向連結リスト —— 各要素が次の要素のアドレスだけを持つ。

特徴 list forward_list
メモリ使用 多い 少ない
逆方向走査? ✅ 可 ❌ 不可
使いやすさ ⭐⭐⭐⭐ ⭐⭐(上級者向け)
💡 推奨: 特別な理由がない限り、std::list を使う。



7. コンテナの選び方

使用場面 推奨コンテナ
動的配列 std::vector
固定サイズ、C配列より安全 std::array
先頭・末尾の高速追加・削除 std::deque
中間の高速挿入・削除 std::list
メモリ節約、片方向で十分 std::forward_list
💡 推奨: ほとんどの場合 std::vector を使う。特別な要件がある場合だけ他のコンテナを検討。



8. 実践例:vector で動的配列を実装(難易度 ⭐⭐)

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

struct Student {
    std::string name;
    int age;
    double score;
};

int main() {
    std::vector<Student> students;
    
    // 学生を追加
    students.push_back({"Alice", 20, 92.5});
    students.push_back({"Bob", 21, 88.0});
    students.push_back({"Charlie", 19, 95.0});
    
    // 出力
    for (const auto& s : students) {
        std::cout << "名前:" << s.name 
                  << "、年齢:" << s.age 
                  << "、点数:" << s.score << std::endl;
    }
    
    return 0;
}

❓ よくある質問

Q: vector と array の違いは? A:

  • vector は動的、サイズ可変、ヒープメモリ
  • array は固定サイズ、スタックメモリ

サイズが変わる場合、vector を使う;サイズが固定なら、array を使う。

Q: vector で範囲for文を使うべき? A: はい。より簡潔で、ループ条件を書く必要がない。

CPP
// 昔の書き方(条件を書く)
for (size_t i = 0; i < vec.size(); i++) { ... }

// 範囲for文(簡潔、推奨)
for (int x : vec) { ... }

Q: list と vector の使い分けは? A: 使い分け:

  • ランダムアクセスが多い(vec[100])、vector が高速
  • 挿入・削除が多い、list が高速

📖 まとめ


📝 練習問題

  1. 初級(難易度 ⭐): std::vector<int> に5つの整数を追加し、出力。

  2. 中級(難易度 ⭐⭐): std::vector<std::string> に3つの文字列をユーザー入力で追加し、出力。

  3. 上級(難易度 ⭐⭐⭐): std::deque で「回文判定」を実装:

    • 文字を先頭と末尾から比較
    • 例:"racecar" は回文、"hello" は違う


9. 🚀 次のステップ

STL コンテナを理解したら、次は STL アルゴリズム(レッスン35) —— 標準ライブラリのアルゴリズムでコンテナを操作、ソートや検索を自分で書かなくていい……!

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%