モダンC++とCでの代替手法

C++のSTLのコンテナとアルゴリズム

このレッスンでは、Cで配列を処理するループを自分で書く方法と、C++標準ライブラリの既製のアルゴリズムを組み合わせる方法を比べます。

はじめに

C++標準ライブラリ(STL)には、vectorのようなコンテナと、絞り込み、合計、並べ替えといった多くの既製のアルゴリズムがあります。これらのアルゴリズムはイテレーターの範囲に対して動くので、処理の内容とデータの保存方法を切り離せます。

大切なポイント

  • C++の抽象化を学ぶ前に、Cでのやり方を理解しましょう。
  • RAIIと値のセマンティクス(value semantics)で、リソースの持ち主を表しましょう。
  • マクロや型変換より、C++の型安全な道具を優先しましょう。

CとC++のコード例

C
実行 →
main.c
#include <stdio.h>

int main(void) {
    int values[] = {3, 8, 2, 7, 6};
    int even[5];
    int count = 0;
    int sum = 0;
    for (int index = 0; index < 5; ++index) {
        if (values[index] % 2 == 0) {
            even[count++] = values[index];
        }
    }
    for (int index = 0; index < count; ++index) {
        sum += even[index];
    }
    printf("count=%d sum=%d\n", count, sum);
}
実行結果
count=3 sum=16
C++
実行 →
main.cpp
#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>

int main() {
    std::vector values{3, 8, 2, 7, 6};
    std::vector<int> even;
    std::copy_if(values.begin(), values.end(),
                 std::back_inserter(even),
                 [](int value) { return value % 2 == 0; });
    std::cout << "count=" << even.size()
              << " sum="
              << std::accumulate(even.begin(), even.end(), 0) << '\n';
}
実行結果
count=3 sum=16

CとC++の比較

Cのバージョンでは、偶数を取り出して合計するために、すべてのループを書き、配列evenの大きさも自分で管理しなければなりません。C++のバージョンはvectorに対してstd::copy_ifで絞り込み、std::accumulateで合計します。コードは短く再利用しやすくなり、計算量も自分で書いた場合と同じくらいはっきりしています。

C

Cは名前付けの習慣、コールバック、マクロ、文脈を持つstructを使います。

C++

C++はスコープがはっきりした型安全な抽象化を用意しており、実行時のコストはふつうかかりません。

発展問題

両方のバージョンを実行し、コードを書き換えて、それぞれの言語がもたらす安全性の違いを観察しましょう。

  • まずCで仕組みを書き、その後で対応するC++の機能を使いましょう。
  • 手作業のリソース解放をRAIIに置き換えましょう。
  • その機能がメモリの確保や仮想関数の呼び出しを生むかどうかを確認しましょう。

チャレンジで練習する

このレッスンの内容を使って実際の問題を解きましょう。各チャレンジはブラウザで動き、すぐにテストされ、AI のレビューも受けられます。

すべてのチャレンジ