Exception caught by value

catch оператор принимает объект по значению

Описание

Этот дефект возникает, когда catch оператор принимает объект по значению.

Риск

Если a 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 объект по значению. Захват исключения по значению приводит к копированию объекта. Это может привести к неопределенному поведению исключения в случае сбоя копирования.

Коррекция: Catch Исключение по ссылке

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

#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++
По умолчанию: On для рукописного кода, off для сгенерированного кода
Синтаксис командной строки: EXCP_CAUGHT_BY_VALUE
Влияние: Средний
Введенный в R2015b