exponenta event banner

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

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