如何编写从 std::invalid_argument 派生的自定义异常 class?
How to write a custom exception class derived from std::invalid_argument?
我应该如何编写一个高效的异常 class 来显示可以通过在 运行-time 之前修复源代码错误来避免的错误?
这就是我选择std::invalid_argument
的原因。
我的异常 class(显然不起作用):
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( );
}
一个 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;
}
如您所见,我需要将 Exception_Msg
与几个子字符串连接起来才能形成完整的消息。这些子字符串不仅是字符串文字,而且是来自静态 std::unordered_set<char>
的 constexpr int
s 和 char
s。这就是我使用 std::string 的原因,因为它具有易于使用的 string::operator+=
。不用说,我的目标是将堆分配减少到只有 1。
另一个非常重要的问题是我应该在哪里放置处理程序( try-catch )?在 main()
内包裹 setCharacter()
或将其保留在 setCharacter
?
内
请制作一个与上述类似的良好且标准的自定义异常class。或者自己写。提前致谢。
而不是每次 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 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 override {
return "A string literal to be appended, "
"another string, "
"yet another one";
}
我根据别人通过评论和回答收到的反馈解决了这个问题。所以我决定在这里留下我自己的 answer/solution 供未来的读者使用。
下面是我经过深思熟虑和研究后得出的结论。这个解决方案相当简单易读。
这里是异常class 接口:
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;
}
变更摘要:
注意不需要 what()
函数,因为编译器会隐式生成它,因为 Foo_Exception
继承自 std::invalid_argument
.
此外,创建 异常消息 的过程已从 Foo_Exception
的构造函数移至函数体 setCharacter
实际上抛出上述异常。这样,Foo_Exception
的构造函数不负责创建消息。相反,它是在抛出的函数体中创建的,然后传递给 Foo_Exception
的构造函数以初始化新的异常对象。
数据成员 std::string Exception_Msg
也已从 Foo_Exception
中删除,因为不再需要它。
最后,try-catch 块被移动到 main()
以便它现在环绕 setCharacter()
并捕获 Foo_Exception
它可能抛出的对象。
最后一句话:
非常感谢任何进一步改进我的答案的建议。
非常感谢所有反馈。
我应该如何编写一个高效的异常 class 来显示可以通过在 运行-time 之前修复源代码错误来避免的错误?
这就是我选择std::invalid_argument
的原因。
我的异常 class(显然不起作用):
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( );
}
一个 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;
}
如您所见,我需要将 Exception_Msg
与几个子字符串连接起来才能形成完整的消息。这些子字符串不仅是字符串文字,而且是来自静态 std::unordered_set<char>
的 constexpr int
s 和 char
s。这就是我使用 std::string 的原因,因为它具有易于使用的 string::operator+=
。不用说,我的目标是将堆分配减少到只有 1。
另一个非常重要的问题是我应该在哪里放置处理程序( try-catch )?在 main()
内包裹 setCharacter()
或将其保留在 setCharacter
?
请制作一个与上述类似的良好且标准的自定义异常class。或者自己写。提前致谢。
而不是每次 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 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 override {
return "A string literal to be appended, "
"another string, "
"yet another one";
}
我根据别人通过评论和回答收到的反馈解决了这个问题。所以我决定在这里留下我自己的 answer/solution 供未来的读者使用。
下面是我经过深思熟虑和研究后得出的结论。这个解决方案相当简单易读。
这里是异常class 接口:
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;
}
变更摘要:
注意不需要
what()
函数,因为编译器会隐式生成它,因为Foo_Exception
继承自std::invalid_argument
.此外,创建 异常消息 的过程已从
Foo_Exception
的构造函数移至函数体setCharacter
实际上抛出上述异常。这样,Foo_Exception
的构造函数不负责创建消息。相反,它是在抛出的函数体中创建的,然后传递给Foo_Exception
的构造函数以初始化新的异常对象。数据成员
std::string Exception_Msg
也已从Foo_Exception
中删除,因为不再需要它。最后,try-catch 块被移动到
main()
以便它现在环绕setCharacter()
并捕获Foo_Exception
它可能抛出的对象。
最后一句话: 非常感谢任何进一步改进我的答案的建议。 非常感谢所有反馈。