Exception caught by value

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++
Язык: C++
Значение по умолчанию: На для рукописного кода, прочь для сгенерированного кода
Синтаксис командной строки: EXCP_CAUGHT_BY_VALUE
Удар: носитель
Введенный в R2015b