Исключение отловлено значением

Оператор 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 значением. Ловля исключения значением вызывает копирование объекта. Это может вызвать неопределенное поведение исключения, если копия перестала работать.

Исправление: отловите исключение ссылкой

Одно возможное решение состоит в том, чтобы отловить исключение ссылкой.

#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 отловлен.

Исправление — исключения выгоды ссылкой

Одно возможное исправление должно отловить исключения ссылкой.

#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++
Значение по умолчанию: на
Синтаксис командной строки: EXCP_CAUGHT_BY_VALUE
Влияние: носитель

Введенный в R2015b