Свой класс exception

Я создал свой класс MyException

class MyException: public std::exception
{
private:
    std::string msg;
public:
    MyException(std::string msg): std::exception(msg)
    {
        
    }
};

Пример взят из интернета, но у меня ругается компилятор (gcc) на строчку std::exception(msg)

note: candidate: 'constexpr std::exception::exception(const std::exception&)'
no matching function for call to 'std::exception::exception(std::__cxx11::string&)'
     MyException(std::string msg): std::exception(msg){
no known conversion for argument 1 from 'std::__cxx11::string' {aka 'std::__cxx11::basic_string<char>'} to 'const std::exception&'

После нашел другой пример

class MyException: public std::exception
{
private:
    
public:
    MyException(std::string msg);
    ~MyException() = default;
    const char* what() const noexcept override;
};

Тут все работает, но у меня есть пару вопросов:

  1. Почему я не могу реализовать первый пример, хотя у другого человека получилось? (c++11)
  2. Почему в строчке const char(указатель) what() const noexcept override; используется последовательность const noexcept override;? Почему я не могу написать просто noexcept override или просто override. Насколько я знаю noexcept не позволяет выбросить исключение. И почему используется два раза const? Мы же уже указали, что функция будет константная

Ответы (3 шт):

Автор решения: AR Hovsepyan
  1. Наверное вы не внимательно смотрели, или там была опечатка, потому что конструктор std::exception не принимает в аргумент std::string, а принимает только С_строку(в некоторых реализациях). Поэтому нужно ему передать именно такую строку. Вот, например, так:

    MyException(std::string msg) 
        : std::exception(msg.c_str())...
    
  2. спецификатор const noexcept override может быть только для функции члена. Это значит, что функция член определена и для константных объектов (то есть она не изменяет состояние объекта), не генерирует исключение(помощь компилятору) и переопределен в производном классе(то есть это виртуальная функция_член).

А второй констант относится к возвращаемому типу(возвращает указатель на константную строку.

→ Ссылка
Автор решения: Harry

Дело в том, что по стандарту exception не имеет конструктора иного, кроме как по умолчанию. введите сюда описание изображения

Так что формально ваш код

MyException(std::string msg): std::exception(msg)

ошибочен. Другое дело, что некоторые компиляторы от стандарта отходят и допускают

exception::exception(const string&)

Так что по-хорошему, хранить сообщение должны вы сами. Или использовать в качестве родительского иной класс.

→ Ссылка
Автор решения: HolyBlackCat

В соседнем ответе объяснили, в чем ошибка. А теперь как чинить.

Да, можно положить в свой класс std::string с текстом ошибки, и перегрузить what(), чтобы он его возвращал. Но есть нюанс: стандартные исключения можно копировать, гарантированно не получая исключений (например от нехватки памяти) - у них внутри какой-то аналог std::shared_ptr<std::string>.

А ваше исключение при копировании сможет выбросить исключение (если new кинет исключение) - маловероятно, но все равно не по фен-шую.

Чтобы этого не произошло, можно не хранить строку самому, а унаследоваться от std::runtime_error или std::logic_error, и хранить строку в нем. Или, если совсем не хочется наследоваться, хранить один из этих классов в своем.

→ Ссылка