如何编写从 std::invalid_argument 派生的自定义异常类?

dig*_*evo 5 c++ exception c-strings stdstring micro-optimization

我应该如何编写一个高效的异常类来显示可以通过在运行时修复源代码错误来防止的错误?

这就是我选择的原因std::invalid_argument

我的异常类(显然不起作用):

class Foo_Exception : public std::invalid_argument
{
private:
    std::string Exception_Msg;
public:
    explicit Foo_Exception( const std::string& what_arg );
    virtual const char* what( ) const throw( );
};

explicit Foo_Exception::Foo_Exception( const std::string& what_arg ) // how should I write this function???
{
    Exception_Msg.reserve( 130000 );

    Exception_Msg = "A string literal to be appended, ";
    Exception_Msg += std::to_string( /* a constexpr int */ );
    Exception_Msg += /* a char from a const unordered_set<char> */;
}

const char* Foo_Exception::what( ) const throw( )
{
    return Exception_Msg.c_str( );
}
Run Code Online (Sandbox Code Playgroud)

if抛出的块Foo_Exception

void setCharacter( const char& c )
{
    if ( /* an invalid character (c) is passed to setCharacter */ )
    {
        try
        {
            const Foo_Exception foo_exc;
            throw foo_exc;
        }
        catch( const Foo_Exception& e )
        {
            std::cerr << e.what( );
            return;
        }
    }

    /*
        rest of the code
    */
}

int main( )
{
    setCharacter( '-' ); // dash is not acceptable!

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我需要连接Exception_Msg一些子字符串才能形成完整的消息。这些子字符串不仅是字符串文字,也是来自 static 的constexpr ints 和s 。这就是我使用 std::string 的原因,因为它具有易于使用的功能。不用说,我的目标是将堆分配减少到只有 1。charstd::unordered_set<char>string::operator+=

另一个非常重要的问题是我应该将处理程序( try-catch )放在哪里?main()放在包装纸里面setCharacter()还是放在里面setCharacter

请制作一个与上面类似的良好且标准的自定义异常类。或者自己写。提前致谢。

dig*_*evo 1

我根据其他人通过评论和答案收到的反馈解决了这个问题。所以我决定在这里为未来的读者留下我自己的答案/解决方案。

下面是我经过深思熟虑和研究后得出的结论。这个解决方案相当简单且可读。

这是异常类接口

Foo_Exception.h

#include <exception>


class Foo_Exception : public std::invalid_argument
{
public:
    explicit Foo_Exception( const std::string& what_arg );
};
Run Code Online (Sandbox Code Playgroud)

这是它的实现

Foo_Exception.cpp

#include "Foo_Exception.h"


Foo_Exception::Foo_Exception( const std::string& what_arg )
: std::invalid_argument( what_arg )
{
}
Run Code Online (Sandbox Code Playgroud)

抛出以下错误函数Foo_Exception

Bar.cpp

#include "Bar.h"
#include "Foo_Exception.h"


void setCharacter( const char& c )
{
    if ( /* an invalid character (c) is passed to setCharacter */ )
    {
        std::string exceptionMsg;
        exceptionMsg.reserve( 130000 );

        exceptionMsg = "A string literal to be appended, ";
        exceptionMsg += std::to_string( /* a constexpr int */ );
        exceptionMsg += /* a char from a const unordered_set<char> */;

        throw Foo_Exception( exceptionMsg );
    }

    /*
        rest of the code
    */
}
Run Code Online (Sandbox Code Playgroud)

异常处理方法:

main.cpp

#include <iostream>
#include "Bar.h"
#include "Foo_Exception.h"


int main( )
{
    try
    {
        setCharacter( '-' ); // The dash character is not valid! Throws Foo_Exception.
    }
    catch ( const Foo_Exception& e )
    {
        std::cerr << e.what( ) << '\n';
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

变更摘要:

  1. what()请注意,由于编译器隐式生成函数,因此不需要函数,因为Foo_Exception它继承自std::invalid_argument.

  2. 此外,创建异常消息的过程已从's 构造函数移至实际引发上述异常的Foo_Exception函数主体。setCharacter这样,Foo_Exception的 ctor 就不负责创建消息。相反,它是在抛出异常的函数体内创建的,然后传递给 的 ctorFoo_Exception来初始化新的异常对象。

  3. 数据成员std::string Exception_Msg也被删除,Foo_Exception因为不再需要它。

  4. 最后,try-catch块被移动,main()以便它现在环绕setCharacter()并捕获Foo_Exception它可能抛出的对象。

最后一句话: 非常感谢任何进一步改进我的答案的建议。非常感谢您的所有反馈。