【问题标题】:C++ Custom Exception classesC++ 自定义异常类
【发布时间】:2021-08-24 15:53:00
【问题描述】:

我正在制作一个程序,并决定创建自己的例外,所以我编写了以下仅头文件:

#ifndef ARGUMENT_EXCEPTIONS
#define ARGUMENT_EXCEPTIONS

#include <exception>


namespace AAerr {

    class ArgumentException : public std::exception {
    private:
        const char* msg;
        static constexpr char* funcName = (char*)"ArgumentException";
    public:
        ArgumentException(const char* msg_) {
            msg = msg_;
        }

        const char* getMessage() {
            return msg;
        }

        virtual const char* what() const throw() {
            return funcName;
        }
    };


    class WrongReturnType : public ArgumentException {
    private:
        const char* msg = "Wrong Type";
        char requestedType;
        char ofType;
        static constexpr char* funcName = (char*)"WrongReturnType";
    public:
        WrongReturnType(const char requested, const char is) : ArgumentException(msg) {
            requestedType = requested;
            ofType = is;
        }


        char get_requested_type() {
            return requestedType;
        }


        char get_of_type() {
            return ofType;
        }

        virtual const char* what() {
            return funcName;
        }
    };

}

#endif // ARGUMENT_EXCEPTIONS

当我试图在我的程序中抛出并捕捉其中一个时,它从未捕捉到任何东西:

#include "exception_header_file.hpp" // the name of the header file
#include <iostream>

int main() {
    try {
        throw AAerr::ArgumentException("TEST");
    } catch (AAerr::ArgumentException& exc) {
        std::cout << "CAUGHT EXCEPTION" << std::endl; // never executed
    }
}

然后我制作了第二个文件(只是为了找出问题所在):

#include <iostream>

#include <exception>

namespace AAerr {

    class Exc : public std::exception {
        private:
            const char* msg;
            static constexpr char* funcName = (char*)"TEST FUNC";
        public:
            Exc(const char* msg_) {
                msg = msg_;
            }

            const char* getMessage() {
                return msg;
            }

            virtual const char* what() {
                return funcName;
            }
    };

    class Exc2 : public Exc {
        private:
            int line;
            static constexpr char* funcName = (char*)"FUNCTION";
        public:
            Exc2(const char* msg_, int line_) : Exc(msg_) {line = line_;}
            virtual const char* what() {
                return funcName;
            }
    };
};

int main() {
    try {
        throw Exc2("TEST", 5);
    } catch (AAerr::Exc& exc) {
        std::cout << "CAUGHT EXCEPTION" << std::endl; // works fine
    }
}

谁能帮我找出问题所在??我找不到这两个之间的任何区别。

编译器:g++(gcc) 平台:ubuntu(linux)

编辑: 我设法解决了这个问题。

它在链接器(ld)上。

我更改了我的 Makefile 来构建整个项目,而不是先制作然后链接所有内容。

我的意思是,我做到了:

build:
    g++ program_part1.cpp program_part2.cpp program_part3.cpp -o example.elf

代替:

build: part1.o part2.o part3.o
    g++ part1.o part2.o part3.o -o output.elf

part1.o: program_part1.cpp program_part1.hpp
    g++ -c program_part1.cpp -o part1.o

...
...

【问题讨论】:

  • 对于使用 RTTI 的事物(捕获异常正在使用它),不要使用仅标头类更安全。使用动态库时可能会出现问题(您的问题没有描述)。
  • 您的代码按预期工作,尽管您在初始化之前使用了成员变量msggodbolt.org/z/T8xqqqcsz
  • 不确定这是否会导致问题,但是:msg = msg_; 对初始化字符串成员变量是否正确?看起来ArgumentExceptionWrongReturnType 实际上在他们的what 方法上有不同的签名,我不确定这是多么刻意。

标签: c++ exception try-catch


【解决方案1】:

我怀疑问题出在“主程序”中,请参阅其他答案中的 OP 评论:

是的,我试过了,结果是一样的。它在我的主程序上不起作用,但在我的测试程序上运行良好 – user898238409

如果“主程序”正在使用动态库并且异常被定义为“仅标题”,这可能导致该类多次生成 RTTI(运行时类型信息)的情况。每个包含一个包含此头文件的动态库和主可执行文件。

例如可以这样:

  1. 动态库在发生异常时使用为该库生成的 RTTI 创建类 AAerr::ArgumentException 的实例,并将其作为异常抛出。
  2. 主可执行文件正在尝试使用为该可执行文件构建的 RTTI 捕获该异常。

由于这两个 RTTI 彼此不匹配,因此 catch 语句无法注意到引发了预期的异常。

正确的解决方法是删除“仅标题”异常,因此所有虚拟方法都应在 cpp 文件中定义。这将导致与特定库的明确关联。因此,ArgumentExceptionWrongReturnType 将只有一个 RTTI。

【讨论】:

  • 所以你的意思是我需要像普通程序(.hpp 和 .cpp 文件)一样进行例外处理?
  • 首先澄清你有动态库(可能编辑你的问题)。如果是,那么“是”。基本上你必须强制链接器为这些类只生成一个 RTTI。
  • 如果不试试这个:stackoverflow.com/a/38901400/1387438
【解决方案2】:

您是否尝试过捕获 std::exception 而不是异常类?

像这样:

try{
throw AAerr::Argument exception("Test");
} catch (std::exception exc) {
std::cout << "HEY" << std::endl;
}

【讨论】:

  • 是的,我试过了,结果是一样的。它不适用于我的主程序,但在我拥有的测试程序上运行良好
  • 请定义“主程序”并在问题下查看我的评论!
  • 由于对象切片,按值捕获基类是一个危险的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-02
  • 2012-03-26
  • 1970-01-01
  • 1970-01-01
  • 2010-12-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多