Как создать класс исключений, который сообщает, какие файлы и номера строк в C ++? - PullRequest
0 голосов
/ 08 января 2020

Проблема

Я пытаюсь создать класс Exception, который может быть выведен из throw ошибок, которые сообщают полезную информацию, такую ​​как номер строки и файл происхождения.

Код

#include <iostream>
#include <stdexcept>
#include <sstream>
using namespace std;


class Exception : public std::logic_error {
    const char *msg;
    std::string line;
    std::string file;

    std::string build_exception() const {
        std::ostringstream stream;
        stream << file << ":" << line << ": " << msg << std::endl;
        return stream.str();
    }

public:
    explicit Exception(const char *msg) : msg(""), std::logic_error(build_exception()) {};

    Exception(const char *msg, const std::string &file, int line) :
            msg(msg),
            std::logic_error(build_exception()) {}

    ~Exception() noexcept override = default;

    Exception(Exception const &other) noexcept(true): msg(other.msg), logic_error(build_exception()) {};

    Exception &operator=(Exception const &other) = default;

    const char *what() const noexcept override {
        return build_exception().c_str();
    }

};


class AnotherError : public Exception {
public:
    using Exception::Exception;
};


int main() {

    throw AnotherError("with this message ", __FILE__, __LINE__);
    return 0;
};

Токовый выход

terminate called after throwing an instance of 'AnotherError'
  what():  :: with this message


Желаемый выход

Я хочу, чтобы объект AnotherError был выдан с сообщением <filename>:<line_number>: with this message

1 Ответ

3 голосов
/ 08 января 2020

Эта функция:

const char *what() const noexcept override {
    return build_exception().c_str();
}

ведет к UB, когда вы возвращаете висячий указатель (вы вызываете c_str() для временного std::string, который уничтожается в конце выражения). Также вам не хватает кода в вашем конструкторе, который устанавливает члены file и line.

Я считаю, что самым простым решением было бы хранить std::string с сообщением об ошибке внутри этого класса (и вам не нужно было бы хранить msg, file и line отдельно). С другой стороны, если вы хотите просто использовать std::logic_error для предоставления сообщения об ошибке, вы должны удалить переопределение виртуальной функции what():

class Exception : public std::logic_error {
    static std::string build_exception( const char *msg, const char *file = "", int line = 0 )  {
        std::ostringstream stream;
        stream << file << ":" << line << ": " << msg << std::endl;
        return stream.str();
    }

public:
    explicit Exception(const char *msg) std::logic_error(build_exception(msg)) {};

    Exception(const char *msg, const char *file, int line) :
            std::logic_error(build_exception(msg,file,line)) {}
};
...