固定長・可変長配列を実装するC++シーケンシャルコンテナ

固定長シーケンシャルコンテナ FixedArrayList

コンパイル時に要素数が確定する、スタック領域を利用したシンプルなリストである。全要素が連続したメモリブロックに格納され、ランダムアクセスがO(1)で行える。

// FixedArrayList.hpp
#pragma once
#include "LinearList.hpp"

namespace ds {

template<typename T, std::size_t N>
class FixedArrayList : public LinearList<T> {
protected:
    T buffer_[N];                 // 静的配列による連続領域
public:
    FixedArrayList() noexcept {
        this->data_   = buffer_; // 基底クラスにバッファを渡す
        this->size_   = 0;
    }

    [[nodiscard]] constexpr std::size_t max_size() const noexcept {
        return N;
    }
};

} // namespace ds

可変長シーケンシャルコンテナ HeapArrayList

実行時に容量を決定し、ヒープ領域から動的にメモリを確保する。必要に応じて容量を拡張・縮小できるため、柔軟性が高い。

リサイズ時の安全性要件

  • メモリリークを起こさない
  • 既存データの整合性を保つ
  • 例外発生時もオブジェクトは利用可能な状態を維持
// HeapArrayList.hpp
#pragma once
#include "LinearList.hpp"
#include "MemoryException.hpp"

namespace ds {

template<typename T>
class HeapArrayList : public LinearList<T> {
protected:
    std::size_t cap_;  // 現在確保済みの容量
public:
    explicit HeapArrayList(std::size_t initial_cap)
        : cap_(initial_cap) {
        this->data_ = new T[cap_];
        if (!this->data_) {
            throw MemoryException("Failed to allocate HeapArrayList");
        }
        this->size_ = 0;
    }

    [[nodiscard]] std::size_t capacity() const noexcept {
        return cap_;
    }

    void reserve(std::size_t new_cap) {
        if (new_cap == cap_) return;

        T* new_block = new(std::nothrow) T[new_cap];
        if (!new_block) {
            throw MemoryException("Reserve failed: out of memory");
        }

        const std::size_t copy_len = (this->size_ < new_cap) ? this->size_ : new_cap;
        for (std::size_t i = 0; i < copy_len; ++i) {
            new_block[i] = std::move(this->data_[i]);
        }

        T* old_block = this->data_;

        this->data_ = new_block;
        this->size_ = copy_len;
        cap_        = new_cap;

        delete[] old_block;   // 古いブロックを解放
    }

    ~HeapArrayList() {
        delete[] this->data_;
    }
};

} // namespace ds

使用例

// main.cpp
#include "FixedArrayList.hpp"
#include "HeapArrayList.hpp"
#include <iostream>

int main() {
    // 固定長リスト
    ds::FixedArrayList<int, 4> fixed;
    for (int v : {7, 3, 9, 2}) fixed.push_back(v);
    std::cout << "Fixed capacity: " << fixed.max_size() << '\n';

    // 可変長リスト
    ds::HeapArrayList<double> dyn(3);
    dyn.push_back(1.2);
    dyn.push_back(3.4);
    dyn.push_back(5.6);
    dyn.reserve(6);   // 容量を拡張
    dyn.push_back(7.8);
    std::cout << "Dynamic capacity: " << dyn.capacity() << '\n';
}

タグ: C++ template-metaprogramming dynamic-array exception-safety RAII

6月18日 18:00 投稿