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



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

这就是我选择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( );
}

抛出Foo_Exceptionif块:

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;
}

如您所见,我需要将Exception_Msg与几个子字符串连接起来,以形成完整的消息。这些子字符串不仅是字符串文字,而且是静态std::unordered_set<char>中的constexpr ints 和chars。这就是为什么我使用 std::string,因为它具有易于使用的string::operator+=。不用说,我的目标是将堆分配减少到只有 1。

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

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

与其每次都new char[],为什么不让一个std::string数据成员呢?

class Foo_Exception : public std::exception /* ? */
{
std::string msg;
public:
Foo_Exception() {
msg.reserve( 130000 );
msg = "A string literal to be appended, ";
msg += "another string, ";
msg += "yet another one";
}
const char * what() const noexcept override { return msg.data(); }
/* other members ? */
}

或者,您可以从std异常类型之一派生,该异常类型将字符串作为构造上的参数

class Foo_Exception : public std::runtime_error /* or logic_error */
{
public:
Foo_Exception() : runtime_error("A string literal to be appended, " "another string, " "yet another one") {}
/* other members ? */
}

但是,如果只有字符串文本,则可以将它们拆分到多个源行上,并且分配为零

const char * what() const noexcept override { 
return "A string literal to be appended, "
"another string, "
"yet another one";
}

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

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

下面是异常类接口

Foo_Exception.h

#include <exception>

class Foo_Exception : public std::invalid_argument
{
public:
explicit Foo_Exception( const std::string& what_arg );
};

这是它的实现

Foo_Exception.cpp

#include "Foo_Exception.h"

Foo_Exception::Foo_Exception( const std::string& what_arg )
: std::invalid_argument( what_arg )
{
}

抛出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
*/
}

如何处理异常

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;
}

更改摘要:

  1. 请注意,由于编译器会隐式生成what()函数,因为Foo_Exceptionstd::invalid_argument继承。

  2. 此外,创建异常消息的过程从Foo_Exception的 ctor 移动到函数的主体setCharacter实际上抛出上述异常。这样,Foo_Exception的 ctor 就不负责创建消息。相反,它是在抛出的函数的主体中创建的,然后传递给Foo_Exception的 ctor 以初始化新的异常对象。

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

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

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

最新更新