C++ファイル入出力における例外処理の実践ガイド

C++でファイル操作を行う際、予期せぬエラーが発生することがあります。これらのエラーに対処するために、例外処理の重要性は非常に高いです。本記事では、C++におけるファイル入出力操作時の例外処理について、基本的な概念から具体的な実装例までを詳しく解説します。これにより、エラーに強い堅牢なプログラムを作成する方法を学びます。

目次

C++における例外処理の基礎

例外処理は、プログラムの実行中に発生する予期しないエラーを捕捉し、適切に処理するためのメカニズムです。C++では、これを実現するためにtry, catch, throwというキーワードが用意されています。

tryブロック

tryブロック内には、エラーが発生する可能性のあるコードが記述されます。ここで例外が投げられると、プログラムの制御は即座にcatchブロックに移ります。

try {
    // エラーが発生する可能性のあるコード
}

catchブロック

catchブロックでは、発生した例外を捕捉し、適切に処理します。例外の型に応じた複数のcatchブロックを用意することも可能です。

catch (const std::exception& e) {
    // 例外処理のコード
    std::cerr << "エラー: " << e.what() << std::endl;
}

throwキーワード

throwキーワードを使って、意図的に例外を発生させることができます。これにより、エラー発生時に特定の処理を実行させることが可能です。

throw std::runtime_error("エラーが発生しました");

C++における基本的な例外処理の流れは以上です。次のセクションでは、ファイル操作における具体的なエラーとその原因について見ていきます。

ファイル操作における一般的なエラー

ファイル操作を行う際には、さまざまなエラーが発生する可能性があります。これらのエラーを予測し、適切に対処することで、プログラムの信頼性を高めることができます。

ファイルが存在しないエラー

指定されたファイルが存在しない場合に発生します。このエラーは、ファイルを開こうとした際に検出されます。

std::ifstream file("non_existent_file.txt");
if (!file) {
    std::cerr << "ファイルが見つかりません" << std::endl;
}

ファイルの権限エラー

ファイルに対する読み取りまたは書き込み権限がない場合に発生します。このエラーは、アクセス権の確認時に検出されます。

std::ofstream file("protected_file.txt");
if (!file) {
    std::cerr << "ファイルにアクセスできません" << std::endl;
}

ディスクスペース不足エラー

ファイルに書き込みを行う際に、ディスクスペースが不足している場合に発生します。このエラーは、書き込み操作中に検出されます。

try {
    std::ofstream file("large_file.txt");
    // 大量のデータを書き込む処理
    if (!file) {
        throw std::runtime_error("ディスクスペースが不足しています");
    }
} catch (const std::runtime_error& e) {
    std::cerr << e.what() << std::endl;
}

ファイルの形式エラー

ファイルの形式が期待するものと異なる場合に発生します。これは、ファイルの読み取り時にデータの整合性を確認することで検出されます。

std::ifstream file("data.csv");
std::string line;
if (file) {
    while (std::getline(file, line)) {
        if (!isValidFormat(line)) {
            std::cerr << "ファイル形式が不正です" << std::endl;
            break;
        }
    }
}

これらの一般的なエラーに対処するために、次のセクションでは、try-catchブロックを使用した具体的な例外処理方法について説明します。

try-catchブロックの使用法

C++で例外処理を行う際の基本となるのが、try-catchブロックです。これを使うことで、エラーが発生した場合にプログラムの異常終了を防ぎ、適切にエラー処理を行うことができます。

基本的なtry-catchブロック

tryブロック内でエラーが発生した場合、throwキーワードを用いて例外を投げ、その例外をcatchブロックで捕捉します。

#include <iostream>
#include <fstream>
#include <stdexcept>

int main() {
    try {
        std::ifstream file("example.txt");
        if (!file) {
            throw std::runtime_error("ファイルを開くことができません");
        }
        // ファイル操作コード
    } catch (const std::runtime_error& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
    }
    return 0;
}

複数のcatchブロック

異なる種類の例外を捕捉するために、複数のcatchブロックを使用することができます。それぞれの例外に対して異なる処理を行うことが可能です。

#include <iostream>
#include <fstream>
#include <stdexcept>

int main() {
    try {
        std::ifstream file("example.txt");
        if (!file) {
            throw std::runtime_error("ファイルを開くことができません");
        }
        // ファイル操作コード
    } catch (const std::runtime_error& e) {
        std::cerr << "ランタイムエラー: " << e.what() << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "一般的な例外: " << e.what() << std::endl;
    }
    return 0;
}

catchブロックでのリソース解放

例外が発生した場合に、開いたファイルなどのリソースを適切に解放することが重要です。catchブロック内で必要なクリーンアップ処理を行います。

#include <iostream>
#include <fstream>
#include <stdexcept>

int main() {
    std::ifstream file;
    try {
        file.open("example.txt");
        if (!file) {
            throw std::runtime_error("ファイルを開くことができません");
        }
        // ファイル操作コード
    } catch (const std::exception& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
    }
    // リソースの解放
    if (file.is_open()) {
        file.close();
    }
    return 0;
}

これらの基本的な例外処理の方法を理解することで、C++プログラムにおけるエラー処理が効果的に行えるようになります。次のセクションでは、標準ライブラリの例外クラスについて詳しく見ていきます。

標準ライブラリの例外クラス

C++標準ライブラリには、多くの汎用的な例外クラスが用意されています。これらを利用することで、より柔軟で強力な例外処理が可能となります。

std::exceptionクラス

すべての例外クラスの基底クラスであり、whatメソッドを持ち、エラーメッセージを返します。独自の例外クラスを作成する際の基礎となります。

#include <iostream>
#include <exception>

try {
    throw std::exception();
} catch (const std::exception& e) {
    std::cerr << "例外: " << e.what() << std::endl;
}

std::runtime_errorクラス

実行時エラーを表す例外クラスで、std::exceptionから派生しています。具体的なエラーメッセージを持たせることができます。

#include <iostream>
#include <stdexcept>

try {
    throw std::runtime_error("実行時エラーが発生しました");
} catch (const std::runtime_error& e) {
    std::cerr << "ランタイムエラー: " << e.what() << std::endl;
}

std::logic_errorクラス

プログラムの論理エラーを表す例外クラスで、std::exceptionから派生しています。主にプログラミングミスを示すために使われます。

#include <iostream>
#include <stdexcept>

try {
    throw std::logic_error("論理エラーが発生しました");
} catch (const std::logic_error& e) {
    std::cerr << "ロジックエラー: " << e.what() << std::endl;
}

その他の標準例外クラス

C++標準ライブラリには他にも多くの例外クラスが存在します。それぞれのクラスは特定のエラー状態を示すために使用されます。

  • std::out_of_range: 範囲外アクセスエラー
  • std::invalid_argument: 無効な引数エラー
  • std::bad_alloc: メモリ割り当て失敗エラー
#include <iostream>
#include <stdexcept>
#include <vector>

try {
    std::vector<int> vec(5);
    int value = vec.at(10); // std::out_of_rangeをスロー
} catch (const std::out_of_range& e) {
    std::cerr << "範囲外アクセス: " << e.what() << std::endl;
}

標準ライブラリの例外クラスを活用することで、エラー処理の質を向上させ、より堅牢なプログラムを作成することができます。次のセクションでは、ファイル入出力時の具体的な例外処理について見ていきます。

ファイル入出力時の具体的な例外処理

ファイルの読み書き操作中に発生する具体的なエラーに対処するための例外処理方法を紹介します。これにより、ファイル操作の信頼性を高めることができます。

ファイルの読み取り時の例外処理

ファイルの読み取り操作で発生する一般的なエラーには、ファイルが存在しない、ファイルにアクセスできないなどがあります。以下はその具体的な例です。

#include <iostream>
#include <fstream>
#include <stdexcept>

void readFile(const std::string& filename) {
    std::ifstream file;
    try {
        file.open(filename);
        if (!file) {
            throw std::runtime_error("ファイルを開くことができません: " + filename);
        }

        std::string line;
        while (std::getline(file, line)) {
            // ファイルの内容を処理
            std::cout << line << std::endl;
        }
    } catch (const std::exception& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
    } finally {
        if (file.is_open()) {
            file.close();
        }
    }
}

int main() {
    readFile("example.txt");
    return 0;
}

ファイルの書き込み時の例外処理

ファイルの書き込み操作で発生するエラーには、書き込み権限がない、ディスクスペースが不足しているなどがあります。以下はその具体的な例です。

#include <iostream>
#include <fstream>
#include <stdexcept>

void writeFile(const std::string& filename) {
    std::ofstream file;
    try {
        file.open(filename);
        if (!file) {
            throw std::runtime_error("ファイルを開くことができません: " + filename);
        }

        file << "このテキストを書き込みます。\n";
    } catch (const std::exception& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
    } finally {
        if (file.is_open()) {
            file.close();
        }
    }
}

int main() {
    writeFile("example.txt");
    return 0;
}

ファイル形式の検証と例外処理

ファイルの内容が期待する形式でない場合には、独自の例外をスローすることが有効です。以下は、CSVファイルの読み取り時に形式を検証する例です。

#include <iostream>
#include <fstream>
#include <stdexcept>
#include <sstream>
#include <vector>

bool isValidCSVFormat(const std::string& line) {
    std::istringstream s(line);
    std::string field;
    std::vector<std::string> fields;
    while (std::getline(s, field, ',')) {
        fields.push_back(field);
    }
    return fields.size() >= 2; // 最低2つのフィールドが必要
}

void readCSVFile(const std::string& filename) {
    std::ifstream file;
    try {
        file.open(filename);
        if (!file) {
            throw std::runtime_error("ファイルを開くことができません: " + filename);
        }

        std::string line;
        while (std::getline(file, line)) {
            if (!isValidCSVFormat(line)) {
                throw std::runtime_error("無効なCSVフォーマット: " + line);
            }
            std::cout << line << std::endl;
        }
    } catch (const std::exception& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
    } finally {
        if (file.is_open()) {
            file.close();
        }
    }
}

int main() {
    readCSVFile("example.csv");
    return 0;
}

これらの具体例を参考にして、C++のファイル入出力操作時に効果的な例外処理を実装できます。次のセクションでは、カスタム例外クラスの作成について説明します。

カスタム例外クラスの作成

C++では、標準ライブラリの例外クラスだけでなく、独自の例外クラスを作成してエラーハンドリングをより柔軟に行うことができます。ここでは、カスタム例外クラスの作成方法とその利点について説明します。

カスタム例外クラスの基本

カスタム例外クラスは、標準ライブラリのstd::exceptionクラスを継承して作成します。独自のメンバ変数やメソッドを追加することで、特定のエラーに対する詳細な情報を提供できます。

#include <iostream>
#include <exception>
#include <string>

class FileException : public std::exception {
private:
    std::string message;
public:
    explicit FileException(const std::string& msg) : message(msg) {}
    const char* what() const noexcept override {
        return message.c_str();
    }
};

int main() {
    try {
        throw FileException("カスタム例外: ファイルエラーが発生しました");
    } catch (const FileException& e) {
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

カスタム例外クラスの拡張

カスタム例外クラスを拡張して、追加の情報(例えばエラーコードやファイル名)を保持することができます。これにより、エラーの診断がより容易になります。

#include <iostream>
#include <exception>
#include <string>

class DetailedFileException : public std::exception {
private:
    std::string message;
    int errorCode;
    std::string fileName;
public:
    DetailedFileException(const std::string& msg, int code, const std::string& file)
        : message(msg), errorCode(code), fileName(file) {}

    const char* what() const noexcept override {
        return message.c_str();
    }

    int getErrorCode() const {
        return errorCode;
    }

    const std::string& getFileName() const {
        return fileName;
    }
};

int main() {
    try {
        throw DetailedFileException("カスタム例外: 詳細なファイルエラーが発生しました", 404, "example.txt");
    } catch (const DetailedFileException& e) {
        std::cerr << e.what() << " (Error Code: " << e.getErrorCode() << ", File: " << e.getFileName() << ")" << std::endl;
    }
    return 0;
}

カスタム例外クラスの利用

カスタム例外クラスを利用することで、特定のエラーに対する処理を明確に分けることができます。これにより、コードの可読性と保守性が向上します。

#include <iostream>
#include <fstream>
#include <exception>
#include <string>

class FileOpenException : public std::exception {
private:
    std::string message;
public:
    explicit FileOpenException(const std::string& msg) : message(msg) {}
    const char* what() const noexcept override {
        return message.c_str();
    }
};

void readFile(const std::string& filename) {
    std::ifstream file;
    try {
        file.open(filename);
        if (!file) {
            throw FileOpenException("ファイルを開くことができません: " + filename);
        }

        std::string line;
        while (std::getline(file, line)) {
            std::cout << line << std::endl;
        }
    } catch (const FileOpenException& e) {
        std::cerr << e.what() << std::endl;
    } finally {
        if (file.is_open()) {
            file.close();
        }
    }
}

int main() {
    readFile("example.txt");
    return 0;
}

カスタム例外クラスを作成することで、エラーハンドリングをより柔軟かつ詳細に行うことができます。次のセクションでは、例外処理を活用した堅牢なプログラムの作成方法について説明します。

例外処理を活用した堅牢なプログラム作成

例外処理を適切に活用することで、プログラムの堅牢性を大幅に向上させることができます。ここでは、例外処理を使って信頼性の高いプログラムを作成する方法について解説します。

堅牢なプログラムの基本原則

堅牢なプログラムを作成するためには、以下の基本原則を守ることが重要です。

  • 予測できるエラーを適切に処理する: 例外処理を活用して、予測できるエラーに対して適切な対応を行います。
  • リソースの管理を徹底する: ファイルやメモリなどのリソースを確実に解放するようにします。
  • ユーザーに適切なフィードバックを提供する: エラーが発生した場合には、ユーザーに対して適切なメッセージを表示します。

例外処理を使ったリソース管理

リソースの管理は堅牢なプログラム作成の鍵となります。try-catchブロックを使って、エラー発生時にリソースを確実に解放する方法を紹介します。

#include <iostream>
#include <fstream>
#include <stdexcept>

void processFile(const std::string& filename) {
    std::ifstream file;
    try {
        file.open(filename);
        if (!file) {
            throw std::runtime_error("ファイルを開くことができません: " + filename);
        }

        // ファイルの処理コード
    } catch (const std::exception& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
    } finally {
        if (file.is_open()) {
            file.close();
        }
    }
}

int main() {
    processFile("example.txt");
    return 0;
}

例外の再スロー

場合によっては、捕捉した例外を再度スローすることが必要になることがあります。これにより、上位の関数でさらに詳細なエラーハンドリングが可能になります。

#include <iostream>
#include <fstream>
#include <stdexcept>

void readFile(const std::string& filename) {
    std::ifstream file;
    file.open(filename);
    if (!file) {
        throw std::runtime_error("ファイルを開くことができません: " + filename);
    }

    // ファイルの処理コード
}

void processFile(const std::string& filename) {
    try {
        readFile(filename);
    } catch (const std::exception& e) {
        std::cerr << "ファイル処理中に例外が発生しました: " << e.what() << std::endl;
        throw;  // 例外の再スロー
    }
}

int main() {
    try {
        processFile("example.txt");
    } catch (const std::exception& e) {
        std::cerr << "メイン関数で例外が捕捉されました: " << e.what() << std::endl;
    }
    return 0;
}

適切なエラーメッセージの提供

エラーが発生した際には、ユーザーに対して適切なフィードバックを提供することが重要です。具体的でわかりやすいメッセージを表示することで、ユーザーは問題を理解しやすくなります。

#include <iostream>
#include <fstream>
#include <stdexcept>

void readFile(const std::string& filename) {
    std::ifstream file;
    try {
        file.open(filename);
        if (!file) {
            throw std::runtime_error("ファイルが見つかりません: " + filename);
        }

        // ファイルの処理コード
    } catch (const std::exception& e) {
        std::cerr << "エラー: " << e.what() << std::endl;
        std::cerr << "ファイルの読み取りに失敗しました。ファイルの存在とアクセス権を確認してください。" << std::endl;
    } finally {
        if (file.is_open()) {
            file.close();
        }
    }
}

int main() {
    readFile("example.txt");
    return 0;
}

これらの方法を用いて、例外処理を活用した堅牢なプログラムを作成することができます。次のセクションでは、例外処理のベストプラクティスについて説明します。

例外処理のベストプラクティス

効果的な例外処理を行うためには、いくつかのベストプラクティスを守ることが重要です。これにより、プログラムの信頼性とメンテナンス性を高めることができます。

例外の乱用を避ける

例外は異常事態を扱うためのものであり、通常の制御フローには使用すべきではありません。例外を乱用すると、コードの可読性とパフォーマンスが低下します。

// 悪い例:通常のフローで例外を使用
try {
    if (value < 0) {
        throw std::invalid_argument("負の値です");
    }
    // 通常の処理
} catch (const std::invalid_argument& e) {
    std::cerr << "エラー: " << e.what() << std::endl;
}

// 良い例:通常のフローではif文を使用
if (value < 0) {
    std::cerr << "エラー: 負の値です" << std::endl;
} else {
    // 通常の処理
}

具体的な例外をキャッチする

catchブロックでは、できるだけ具体的な例外クラスをキャッチするようにします。これにより、エラーの種類に応じた適切な処理が可能となります。

try {
    // エラーが発生する可能性のあるコード
} catch (const std::out_of_range& e) {
    std::cerr << "範囲外エラー: " << e.what() << std::endl;
} catch (const std::invalid_argument& e) {
    std::cerr << "無効な引数: " << e.what() << std::endl;
} catch (const std::exception& e) {
    std::cerr << "一般的な例外: " << e.what() << std::endl;
}

例外メッセージに情報を含める

例外メッセージには、エラーの原因を特定するための情報を含めるようにします。これにより、デバッグが容易になります。

#include <iostream>
#include <fstream>
#include <stdexcept>

void readFile(const std::string& filename) {
    std::ifstream file;
    try {
        file.open(filename);
        if (!file) {
            throw std::runtime_error("ファイルを開くことができません: " + filename);
        }
        // ファイルの処理コード
    } catch (const std::exception& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
    } finally {
        if (file.is_open()) {
            file.close();
        }
    }
}

int main() {
    readFile("example.txt");
    return 0;
}

例外の再スローを適切に使用する

必要に応じて例外を再スローし、上位の関数で処理を行うことができます。再スローする際には、元の例外情報を保持することが重要です。

#include <iostream>
#include <fstream>
#include <stdexcept>

void readFile(const std::string& filename) {
    std::ifstream file;
    file.open(filename);
    if (!file) {
        throw std::runtime_error("ファイルを開くことができません: " + filename);
    }
    // ファイルの処理コード
}

void processFile(const std::string& filename) {
    try {
        readFile(filename);
    } catch (const std::exception& e) {
        std::cerr << "ファイル処理中に例外が発生しました: " << e.what() << std::endl;
        throw;  // 例外の再スロー
    }
}

int main() {
    try {
        processFile("example.txt");
    } catch (const std::exception& e) {
        std::cerr << "メイン関数で例外が捕捉されました: " << e.what() << std::endl;
    }
    return 0;
}

例外処理の限界を認識する

すべてのエラーを例外で処理できるわけではありません。例外処理には限界があり、場合によってはプログラムの設計そのものを見直す必要があります。

#include <iostream>
#include <stdexcept>

void riskyOperation() {
    throw std::runtime_error("重大なエラーが発生しました");
}

int main() {
    try {
        riskyOperation();
    } catch (const std::exception& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
        // 必要に応じてプログラムを終了する
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

これらのベストプラクティスを守ることで、C++プログラムにおける例外処理を効果的に行い、プログラムの信頼性を高めることができます。次のセクションでは、理解を深めるための応用例と演習問題を提供します。

応用例と演習問題

ここでは、C++のファイル入出力と例外処理に関する理解を深めるための応用例と演習問題を紹介します。これにより、実践的なスキルを身につけることができます。

応用例1: 設定ファイルの読み込み

設定ファイルを読み込み、その内容を処理するプログラムを作成します。ファイルが存在しない場合や形式が不正な場合には、適切な例外処理を行います。

#include <iostream>
#include <fstream>
#include <stdexcept>
#include <string>

void readConfigFile(const std::string& filename) {
    std::ifstream file;
    try {
        file.open(filename);
        if (!file) {
            throw std::runtime_error("設定ファイルを開くことができません: " + filename);
        }

        std::string line;
        while (std::getline(file, line)) {
            if (line.empty() || line[0] == '#') {
                continue; // 空行やコメント行をスキップ
            }
            // 設定ファイルの処理コード
            std::cout << "設定: " << line << std::endl;
        }
    } catch (const std::exception& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
    } finally {
        if (file.is_open()) {
            file.close();
        }
    }
}

int main() {
    readConfigFile("config.txt");
    return 0;
}

演習問題1: ファイルコピーの例外処理

ファイルをコピーするプログラムを作成し、以下の条件に基づいて例外処理を実装してください。

  • コピー元ファイルが存在しない場合
  • コピー先ファイルに書き込み権限がない場合
  • コピー操作中にエラーが発生した場合
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <string>

void copyFile(const std::string& src, const std::string& dest) {
    std::ifstream srcFile;
    std::ofstream destFile;
    try {
        srcFile.open(src, std::ios::binary);
        if (!srcFile) {
            throw std::runtime_error("コピー元ファイルを開くことができません: " + src);
        }

        destFile.open(dest, std::ios::binary);
        if (!destFile) {
            throw std::runtime_error("コピー先ファイルを開くことができません: " + dest);
        }

        destFile << srcFile.rdbuf();
    } catch (const std::exception& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
    } finally {
        if (srcFile.is_open()) {
            srcFile.close();
        }
        if (destFile.is_open()) {
            destFile.close();
        }
    }
}

int main() {
    copyFile("source.txt", "destination.txt");
    return 0;
}

応用例2: ログファイルのローテーション

ログファイルを一定サイズ以上になった場合にバックアップし、新しいログファイルを作成するプログラムを作成します。ファイル操作中に発生する可能性のあるエラーを例外処理で適切に処理します。

#include <iostream>
#include <fstream>
#include <stdexcept>
#include <string>

void rotateLogFile(const std::string& logFilename, const std::string& backupFilename, std::size_t maxSize) {
    std::ifstream logFile;
    std::ofstream backupFile;
    try {
        logFile.open(logFilename, std::ios::binary);
        if (!logFile) {
            throw std::runtime_error("ログファイルを開くことができません: " + logFilename);
        }

        // ファイルサイズをチェック
        logFile.seekg(0, std::ios::end);
        std::size_t fileSize = logFile.tellg();
        logFile.seekg(0, std::ios::beg);

        if (fileSize > maxSize) {
            // バックアップファイルを作成
            backupFile.open(backupFilename, std::ios::binary);
            if (!backupFile) {
                throw std::runtime_error("バックアップファイルを開くことができません: " + backupFilename);
            }

            // ログファイルの内容をバックアップ
            backupFile << logFile.rdbuf();
            logFile.close();
            backupFile.close();

            // 新しいログファイルを作成
            std::ofstream newLogFile(logFilename, std::ios::trunc);
            if (!newLogFile) {
                throw std::runtime_error("新しいログファイルを作成できません: " + logFilename);
            }
            newLogFile.close();
        }
    } catch (const std::exception& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
    } finally {
        if (logFile.is_open()) {
            logFile.close();
        }
        if (backupFile.is_open()) {
            backupFile.close();
        }
    }
}

int main() {
    rotateLogFile("logfile.txt", "logfile_backup.txt", 1024 * 1024); // 1MB
    return 0;
}

演習問題2: データベース接続の例外処理

データベースに接続し、クエリを実行するプログラムを作成し、以下の条件に基づいて例外処理を実装してください。

  • データベースに接続できない場合
  • クエリの実行に失敗した場合
  • 結果を取得する際にエラーが発生した場合
// データベース接続の疑似コード
#include <iostream>
#include <stdexcept>
#include <string>

class Database {
public:
    void connect(const std::string& connectionString) {
        // 接続処理
        throw std::runtime_error("データベースに接続できません");
    }

    void executeQuery(const std::string& query) {
        // クエリ実行処理
        throw std::runtime_error("クエリの実行に失敗しました");
    }

    std::string fetchResult() {
        // 結果取得処理
        throw std::runtime_error("結果を取得する際にエラーが発生しました");
    }
};

int main() {
    Database db;
    try {
        db.connect("db_connection_string");
        db.executeQuery("SELECT * FROM table");
        std::string result = db.fetchResult();
        std::cout << "クエリ結果: " << result << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "例外が発生しました: " << e.what() << std::endl;
    }
    return 0;
}

これらの応用例と演習問題を通じて、C++におけるファイル入出力と例外処理の実践的なスキルを身につけることができます。次のセクションでは、これまでの内容をまとめます。

まとめ

C++におけるファイル入出力操作は、多くのプログラムで不可欠な機能ですが、エラーが発生しやすい領域でもあります。例外処理を適切に用いることで、エラー発生時のプログラムの異常終了を防ぎ、ユーザーに対して適切なフィードバックを提供しながら、堅牢で信頼性の高いプログラムを作成することができます。

本記事では、C++の基本的な例外処理の方法から始め、標準ライブラリの例外クラス、ファイル操作時の具体的な例外処理、カスタム例外クラスの作成方法、そして実践的な応用例と演習問題までを包括的に解説しました。これらの知識とスキルを活用して、より良いプログラムを開発してください。

コメント

コメントする

目次