メインコンテンツ

例外が値によってキャッチされました

catch ステートメントがオブジェクトを値によって受け取る

説明

この欠陥は、catch ステートメントが値でオブジェクトを受け取った場合に発生します。

リスク

throw ステートメントがオブジェクトを渡し、対応する catch ステートメントが例外を値で受け取る場合、オブジェクトは catch ステートメント パラメーターにコピーされます。このコピーは、次のような予期しない動作の原因となる場合があります。

  • オブジェクトのスライス (throw ステートメントが派生クラス オブジェクトを渡した場合)。

  • 例外の未定義の動作 (コピーが失敗した場合)。

修正方法

例外を参照かポインターによってキャッチします。例外を参照によってキャッチすることを推奨します。

すべて展開する

#include <exception>

extern void print_str(const char* p);
extern void throw_exception();

void func() {
    try {
        throw_exception();
    }

    catch(std::exception exc) {
        print_str(exc.what());
    }
}

この例では、catch ステートメントが std::exception オブジェクトを値により受け取っています。例外を値でキャッチしたことが原因で、オブジェクトのコピーが行われます。これにより、コピーが失敗した場合に例外の動作が未定義となることがあります。

修正: 参照による例外のキャッチ

1 つの解決策として、例外を参照でキャッチします。

#include <exception>

extern void print_str(const char* p);
extern void throw_exception();

void corrected_excpcaughtbyvalue() {
    try {
        throw_exception();
    }
    catch(std::exception& exc) {
        print_str(exc.what());
    }
}
#include <exception>
#include <string>
#include <typeinfo>
#include <iostream>

// Class declarations
class BaseExc {
public:
    explicit BaseExc();
    virtual ~BaseExc() {};
protected:
    BaseExc(const std::string& type);
private:
    std::string _id;
};

class IOExc: public BaseExc {
public:
    explicit IOExc();
};

//Class method declarations
BaseExc::BaseExc():_id(typeid(this).name()) {
}
BaseExc::BaseExc(const std::string& type): _id(type) {
}
IOExc::IOExc(): BaseExc(typeid(this).name()) {
}

int input(void);

int main(void) {
    int rnd = input();
    try {
        if (rnd==0) {
            throw IOExc();
        } else {
            throw BaseExc();
        }
    }

   
    catch(BaseExc exc) {
        std::cout << "Intercept BaseExc" << std::endl;
    }
    return 0;
}

この例では、catch ステートメントが BaseExc オブジェクトを値により受け取っています。例外を値でキャッチしたことが原因で、オブジェクトのコピーが行われます。このコピーは、以下の原因となる場合があります。

  • 例外の未定義の動作 (失敗した場合)。

  • オブジェクトのスライス (派生クラス IOExc の例外がキャッチされた場合)。

修正 — 参照による例外のキャッチ

1 つの修正方法として、例外を参照でキャッチします。

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

// Class declarations
class BaseExc {
public:
    explicit BaseExc();
    virtual ~BaseExc() {};
protected:
    BaseExc(const std::string& type);
private:
    std::string _id;
};

class IOExc: public BaseExc {
public:
    explicit IOExc();
};

//Class method declarations
BaseExc::BaseExc():_id(typeid(this).name()) {
}
BaseExc::BaseExc(const std::string& type): _id(type) {
}
IOExc::IOExc(): BaseExc(typeid(this).name()) {
}

int input(void);

int main(void) {
    int rnd = input();
    try {
        if (rnd==0) {
            throw IOExc();
        } else {
            throw BaseExc();
        }
    }


   
    catch(BaseExc& exc) {
        std::cout << "Intercept BaseExc" << std::endl;
    }
    return 0;
}

結果情報

グループ: C++ の例外
言語: C++
既定値: 手書きコードはオン、生成コードはオフ
コマンド ライン構文: EXCP_CAUGHT_BY_VALUE
影響度: Medium

バージョン履歴

R2015b で導入