派生自std :: exception

时间:2011-01-31 23:15:09

标签: c++ exception-handling

我想从std :: exception派生,以便将特定信息添加到我的日志文件中,但我无法想象如何从std :: exception访问.what()。

此外,我知道在我的异常处理程序中创建一个字符串是不安全的,但我不是这个主题的专家,那么什么是更安全的替代方案呢?

struct Exception : public std::exception, private boost::noncopyable
{
    public:
        Exception(std::string msg)
            : message(msg)
        {}
        ~Exception()
        {}

        virtual const char* what() const throw 
        {
            std::string what = message + // and now what? base.what()
            LOG(what); // write to log file
            return what.c_str();
        }

    private:
        std::string message;
};

编辑: 我真的以错误的方式问我的问题。我对安全性很感兴趣,我只是觉得拥有更多的日志数据会很好。我错了。

现在,我并没有因为消息字符串抛出bad_alloc,以防万一之前有一个bad_alloc,我宁愿有一个简洁的消息。据说我改写了一些东西:

struct Exception : public std::exception
{
    public:
        Exception(std::string msg)
            : message(msg)
        {}
        ~Exception()
        {}

        virtual const char* what() const throw 
        {
            LOG(what); // write to log file
            return what.c_str();
        }

    private:
        std::string message;
};

现在还有任何关于该代码的大问题吗? LOG()抛出std :: exception我出错了,因为我不想通过派生异常类进行无限循环的日志调用,并且该类再次调用log会再次导致相同的异常。 这会像我想要的那样工作,或者我的派生类中的日志记录异常会调用terminate()还是导致核心转储?

4 个答案:

答案 0 :(得分:9)

编辑:自从撰写此答案以来,我偶然发现了Boost文档中的Error and Exception Handling部分。我会在这个答案上推荐这份文件。


首先,让你的例外不可复制是一个坏主意。当你写一些诸如

之类的东西
// could be any exception, doesn't matter.
throw Exception(...);

运行时将该对象的副本创建到特殊位置。有些编译器可能会对此进行优化并在该位置创建原始对象,但The C++ Programming Language表示它是副本,我也相信这是标准所说的,尽管我不确定。您可能会在当前环境中侥幸成功,但情况可能并非总是如此。

然后,其他一切都取决于你在角落案件中的偏执程度。

内存分配部分在异常子句(即构造函数)中基本上是片状的。如果此内存分配失败(即抛出std::bad_alloc),则有两种可能性,具体取决于您编写throw语句的方式:

  1. std::string是在throw语句之前创建的,std::bad_alloc替换了您认为会引发的异常,问题很严重。
  2. std::string是在构造函数调用中内联创建的。如果标准认为“在异常处理期间”,则会调用std::unexpected()/std::terminate()并且您基本上会获得核心转储。
  3. 在任何情况下,您似乎都无法获得报告错误所需的效果。

    我总是建议创建某种不在构造函数中分配内存的临时状态,并等待调用std::what()来创建报告错误的字符串,但这可能仍会导致# 1。您可以使用一些编译时确定的缓冲区大小来确保不会发生。

    很多人会告诉你他们从来没有遇到过在构造函数中分配字符串的问题,因为除非原始异常首先是std::bad_alloc,否则不会引发std::bad_alloc {{1}}。因此,这取决于你的偏执程度。

答案 1 :(得分:4)

我不会深入研究你的代码所带来的无数问题,因为它是一堆巨大的蠕虫。但这是你如何调用基类方法:

std::exception::what()

答案 2 :(得分:3)

这个问题的答案是,除非你明确设置了what()应该从std :: exception返回的值,否则你不想调用它。问题的实际情况是,它会以不同的方式表现出来,并且在不同的实现方式上会有所不同。

请注意,标准在std :: exception中不提供任何功能来提供字符串值。那些实际上通过调用std :: exception :: what()提供有用信息的实现为类添加了额外的非标准功能。例如,MSVC具有exception(char const* const&)构造函数。这不符合标准,你可能不想依赖它。

你最好的选择是永远不要从派生类调用std :: exception :: what。当然,在您的自定义版本中进行upcalls,它们将事物子类化为std :: exception,但不要直接派生。

如果你坚持直接调用这个函数那么你最好检查一下NULL,因为那是你可能会得到的。

答案 3 :(得分:-1)

第二部分。我有几百个kloc,它运行在> 100个平台上,这个平台有一个带有std :: string成员的std :: exception派生类。从来没有遇到任何问题

class myex: public std::exception
{
public:
    std::string m_msg;
    std::string m_className;
    int m_rc;
...