0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C++】エラー処理を分離する try/throw/catch とは

0
Posted at

プログラムが扱うデータは常に正しいとは限りません。
ファイルが存在しない、ゼロ除算が起きた、配列の範囲外にアクセスした――こうした事象は、通常の処理の流れでは対処できない「例外的な事態」です。

C++では、この“異常事態”を通知する仕組みとして 例外(exception) が用意されています。
例外処理を使うことで、通常のロジックとエラー処理を分離し、コードの保守性と信頼性を高めることができます。

本記事ではまず、if分岐によるエラー処理を示し、その後に try/throw/catch による例外処理へ書き換えた例を比較しながら、例外処理の基本を解説します。


1. 分岐によるエラー処理(例外を使わない方法)

まずは、典型的な「戻り値でエラーを通知する」スタイルのコードです。

#include <iostream>
#include <vector>

// valueをチェックし0以上なら2倍した値をresultに入れてtrueを返す
bool process(int value, int& result) {
    if (value < 0) {
        std::cerr << "エラー: 負の値は処理できません(値: " << value << ")\n";
        return false;
    }
    result = value * 2;
    return true;
}

int main() {
    std::vector<int> data = {1, 2, -3, 4, -5};
    for (int i = 0; i < data.size(); ++i) {
        int output;
        if (!process(data[i], output)) {
            std::cerr << "処理失敗(index: " << i << ")\n";
            continue;
        }
        std::cout << "処理成功: " << output << "\n";
    }
    return 0;
}

● このコードのポイント

  • process()負の値を拒否し、false を返す
  • 呼び出し側は if文で毎回エラー判定
  • 正常系と異常系が混在し、ロジックがやや読みにくい

● 実行結果

処理成功: 2
処理成功: 4
エラー: 負の値は処理できません(値: -3)
処理失敗(index: 2)
処理成功: 8
エラー: 負の値は処理できません(値: -5)
処理失敗(index: 4)

このように、戻り値でエラーを通知する方法はシンプルですが、呼び出し側のコードが煩雑になりやすいという欠点があります。


2. try/throw/catch による例外処理

次に、同じ処理を 例外処理 を使って書き直したコードです。

#include <iostream>
#include <vector>
#include <stdexcept>

int process(int value) {
    if (value < 0) {
        throw std::invalid_argument("負の値は処理できません(値: " + std::to_string(value) + ")");
    }
    return value * 2;
}

int main() {
    std::vector<int> data = {1, 2, -3, 4, -5};
    for (int i = 0; i < data.size(); ++i) {
        try {
            int output = process(data[i]);
            std::cout << "処理成功: " << output << "\n";
        } catch (const std::invalid_argument& e) {
            std::cerr << "例外発生(index: " << i << "): " << e.what() << "\n";
        }
    }
    return 0;
}

● 例外処理のポイント

  • process()負の値を見つけたら例外を投げる(throw)
  • 呼び出し側は tryブロックで処理し、catchで例外を受ける
  • 正常系のコードがスッキリし、異常系は catch に集約される

● 実行結果

処理成功: 2
処理成功: 4
例外発生(index: 2): 負の値は処理できません(値: -3)
処理成功: 8
例外発生(index: 4): 負の値は処理できません(値: -5)

3. 分岐と例外の違いを整理する

以下は、両者の特徴を5つの観点で比較した表です。

観点 分岐(戻り値) 例外(throw/catch)
制御の明示性 if文で明示的 例外が非同期的に飛ぶ
コードの簡潔さ エラー判定が増え冗長 正常系がすっきり
パフォーマンス 高速 例外発生時にオーバーヘッド
保守性 分岐が増えると煩雑 例外型で整理しやすい
RAIIとの相性 手動で解放が必要 スタックアンワインドで自動解放

● 例外処理のメリット

  • 正常系のコードが読みやすくなる
  • 異常系を catch に集約できる
  • RAIIと組み合わせるとリソース管理が容易

● 例外処理の注意点

  • 例外は「本当に例外的な事態」に使うべき
  • パフォーマンスが重要な場面では避けることもある

4. まとめ:例外処理は「ロジックの本質に集中する」ための仕組み

戻り値によるエラー処理はシンプルですが、呼び出し側のコードが煩雑になりがちです。
一方、例外処理は 正常系と異常系を分離できるため、コードの見通しが良くなるという大きな利点があります。

特に今回のような「ループ中で異常値を扱う」ケースでは、例外処理を使うことで 本来の処理ロジックに集中できるようになります。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?