第1章:STLの歴史と設計思想

はじめに

ft_containersは、C++標準テンプレートライブラリ(STL)のコンテナを再実装するプロジェクトです。本章では、STLの歴史と設計思想を学び、プロジェクト全体の構造を理解します。

---

1. STLの歴史

1.1 Alexander Stepanovの構想

STLの父、Alexander Stepanovは1970年代からジェネリックプログラミングの研究を続けていました。

年表:
1976: Stepanov、ソ連でジェネリックプログラミングを研究開始
1979: Bjarne Stroustrup、C with Classesを開発
1983: C++誕生
1987: Stepanov、HP研究所に移籍
1988: Ada向けジェネリックライブラリを開発
1992: Andrew Koenig、Stepanovを C++標準化委員会に紹介
1993: Stepanov、C++向けSTLを開発
1994: STLがC++標準に採用
1998: C++98標準化(STL含む)

1.2 Stepanovの設計哲学

> "I believe that iterator theories are as central to Computer Science > as theories of rings or Banach spaces are central to Mathematics." > — Alexander Stepanov

Stepanovの核心的アイデア:

  • アルゴリズムとデータ構造の分離
  • イテレータによる抽象化
  • ゼロオーバーヘッド原則
  • // 従来のアプローチ:各コンテナにソートを実装
    class IntArray {
        void sort();
    };
    class LinkedList {
        void sort();
    };
    
    // STLのアプローチ:アルゴリズムを分離
    template<typename Iterator>
    void sort(Iterator first, Iterator last);
    
    // あらゆるコンテナに適用可能
    std::sort(array.begin(), array.end());
    std::sort(vector.begin(), vector.end());
    

    ---

    2. STLの構成要素

    2.1 コンテナ

    データを格納する構造:

    シーケンスコンテナ:
    +--------+--------+--------+
    | vector | deque  | list   |
    +--------+--------+--------+
    |動的配列|両端配列|双方向  |
    |        |        |リスト  |
    +--------+--------+--------+
    
    連想コンテナ:
    +--------+--------+--------+--------+
    |  set   |multiset|  map   |multimap|
    +--------+--------+--------+--------+
    |一意集合|重複集合|キー値  |重複キー|
    +--------+--------+--------+--------+
    
    コンテナアダプタ:
    +--------+--------+-----------+
    | stack  | queue  |priority_q |
    +--------+--------+-----------+
    |LIFO    |FIFO    |優先度付き |
    +--------+--------+-----------+
    

    2.2 イテレータ

    コンテナとアルゴリズムを繋ぐ抽象化:

    // イテレータのカテゴリ
    InputIterator       // 読み取り専用、前進のみ
    OutputIterator      // 書き込み専用、前進のみ
    ForwardIterator     // 読み書き、前進のみ
    BidirectionalIterator // 読み書き、双方向
    RandomAccessIterator  // 読み書き、ランダムアクセス
    

    イテレータの階層:
                      RandomAccessIterator
                             ↑
                      BidirectionalIterator
                             ↑
                       ForwardIterator
                          ↑     ↑
               InputIterator   OutputIterator
    

    2.3 アルゴリズム

    // 検索
    find, find_if, count, count_if
    
    // ソート
    sort, stable_sort, partial_sort
    
    // 変換
    transform, copy, replace, remove
    
    // 数値
    accumulate, inner_product
    

    2.4 ファンクタ(関数オブジェクト)

    template<typename T>
    struct less {
        bool operator()(const T& a, const T& b) const {
            return a < b;
        }
    };
    
    // 使用例
    std::sort(v.begin(), v.end(), std::less<int>());
    

    ---

    3. ft_containersの要件

    3.1 実装対象

    必須:
    ├── vector<T>
    ├── map<Key, Value>
    ├── stack<T>
    └── set<T> (C++98準拠の場合)
    
    ユーティリティ:
    ├── iterators_traits
    ├── reverse_iterator
    ├── enable_if (C++11風だがC++98で実装)
    ├── is_integral
    ├── equal, lexicographical_compare
    └── pair, make_pair
    

    3.2 C++98準拠

    ft_containersはC++98標準に準拠する必要があります:

    // 使用可能
    template<typename T>
    class vector;
    
    // 使用不可(C++11以降)
    auto, nullptr, constexpr, noexcept
    range-based for, initializer_list
    move semantics, variadic templates
    

    3.3 名前空間

    namespace ft {
        template<typename T, typename Alloc = std::allocator<T> >
        class vector;
    
        template<typename Key, typename T,
                 typename Compare = std::less<Key>,
                 typename Alloc = std::allocator<std::pair<const Key, T> > >
        class map;
    
        // ...
    }
    

    ---

    4. テンプレートの基礎

    4.1 クラステンプレート

    template<typename T>
    class Container {
    private:
        T* _data;
        size_t _size;
    
    public:
        Container() : _data(NULL), _size(0) {}
    
        void push(const T& value) {
            // ...
        }
    
        T& operator[](size_t index) {
            return _data[index];
        }
    };
    
    // 使用
    Container<int> intContainer;
    Container<std::string> stringContainer;
    

    4.2 メンバテンプレート

    template<typename T>
    class vector {
    public:
        // 通常のコンストラクタ
        vector(size_t n, const T& val);
    
        // テンプレートコンストラクタ(範囲)
        template<typename InputIterator>
        vector(InputIterator first, InputIterator last);
    };
    

    4.3 テンプレート特殊化

    // 汎用版
    template<typename T>
    struct is_integral {
        static const bool value = false;
    };
    
    // 特殊化版
    template<>
    struct is_integral<int> {
        static const bool value = true;
    };
    
    template<>
    struct is_integral<char> {
        static const bool value = true;
    };
    

    ---

    5. アロケータ

    5.1 std::allocator

    STLコンテナはアロケータを使用してメモリを管理します:

    template<typename T>
    class allocator {
    public:
        typedef T           value_type;
        typedef T*          pointer;
        typedef T&          reference;
        typedef const T*    const_pointer;
        typedef const T&    const_reference;
        typedef size_t      size_type;
        typedef ptrdiff_t   difference_type;
    
        template<typename U>
        struct rebind {
            typedef allocator<U> other;
        };
    
        pointer allocate(size_type n) {
            return static_cast<pointer>(::operator new(n * sizeof(T)));
        }
    
        void deallocate(pointer p, size_type n) {
            (void)n;
            ::operator delete(p);
        }
    
        void construct(pointer p, const_reference val) {
            new(p) T(val);  // placement new
        }
    
        void destroy(pointer p) {
            p->~T();
        }
    };
    

    5.2 rebind

    異なる型のアロケータを取得:

    // mapでの使用例
    // map<int, string>は内部でノードを確保する
    typedef std::pair<const int, std::string> value_type;
    
    // ノード型
    struct Node {
        value_type data;
        Node* left;
        Node* right;
        // ...
    };
    
    // value_type用アロケータからNode用アロケータを取得
    typedef typename Alloc::template rebind<Node>::other node_allocator;
    

    ---

    6. 例外安全性

    6.1 例外安全性のレベル

    No-throw guarantee(例外を投げない):
    - デストラクタ
    - swap操作
    
    Strong guarantee(強い保証):
    - 例外発生時、操作前の状態を維持
    - insert, push_back(失敗時は変更なし)
    
    Basic guarantee(基本保証):
    - 例外発生時も不変条件を維持
    - リソースリークなし
    

    6.2 実装での考慮

    template<typename T, typename Alloc>
    void vector<T, Alloc>::push_back(const T& value) {
        if (_size == _capacity) {
            // 1. 新しいメモリを確保
            size_t new_cap = _capacity ? _capacity * 2 : 1;
            pointer new_data = _alloc.allocate(new_cap);
    
            try {
                // 2. 既存要素をコピー
                for (size_t i = 0; i < _size; ++i) {
                    _alloc.construct(new_data + i, _data[i]);
                }
                // 3. 新要素を追加
                _alloc.construct(new_data + _size, value);
            } catch (...) {
                // コピー中に例外が発生したら、確保したメモリを解放
                _alloc.deallocate(new_data, new_cap);
                throw;
            }
    
            // 4. 古いデータを破棄
            for (size_t i = 0; i < _size; ++i) {
                _alloc.destroy(_data + i);
            }
            _alloc.deallocate(_data, _capacity);
    
            _data = new_data;
            _capacity = new_cap;
        } else {
            _alloc.construct(_data + _size, value);
        }
        ++_size;
    }
    

    ---

    7. プロジェクト構造

    7.1 ディレクトリ構成

    ft_containers/
    ├── Makefile
    ├── includes/
    │   ├── vector.hpp
    │   ├── map.hpp
    │   ├── stack.hpp
    │   ├── set.hpp (オプション)
    │   ├── iterator.hpp
    │   ├── iterator_traits.hpp
    │   ├── reverse_iterator.hpp
    │   ├── type_traits.hpp (enable_if, is_integral)
    │   ├── utility.hpp (pair, make_pair)
    │   ├── algorithm.hpp (equal, lexicographical_compare)
    │   └── rb_tree.hpp (赤黒木)
    ├── srcs/
    │   └── main.cpp (テスト)
    └── tests/
        ├── vector_test.cpp
        ├── map_test.cpp
        └── ...
    

    7.2 ヘッダーの依存関係

              type_traits.hpp
                   ↑
              iterator_traits.hpp
                   ↑
            ┌──────┴──────┐
            ↓             ↓
      iterator.hpp   reverse_iterator.hpp
            ↓             ↓
            └──────┬──────┘
                   ↓
              vector.hpp
                   ↓
              stack.hpp
    
              rb_tree.hpp
                   ↓
            ┌──────┴──────┐
            ↓             ↓
         map.hpp       set.hpp
    

    ---

    まとめ

    本章で学んだこと:

  • STLの歴史: Stepanovの貢献、ジェネリックプログラミング
  • STLの構成: コンテナ、イテレータ、アルゴリズム
  • ft_containersの要件: 実装対象、C++98準拠
  • テンプレートの基礎: クラステンプレート、特殊化
  • アロケータ: メモリ管理、rebind
  • 例外安全性: 各レベルの保証

次章では、vector(動的配列)の実装を学びます。