C++ 如何在C+中以干净的方式处理异常+;
我的问题是,我正在编写一个程序,它应该是未来可读的,并且该程序有很多异常情况。因此,每当我必须抛出一个异常时,我必须编写10行以上的代码来初始化我的异常类,并将程序中的信息附加到异常类中。例如:C++ 如何在C+中以干净的方式处理异常+;,c++,exception,coding-style,readability,throw,C++,Exception,Coding Style,Readability,Throw,我的问题是,我正在编写一个程序,它应该是未来可读的,并且该程序有很多异常情况。因此,每当我必须抛出一个异常时,我必须编写10行以上的代码来初始化我的异常类,并将程序中的信息附加到异常类中。例如: MyExceptionClass ex; ex.setErrorMessage("PIN_CANNOT_GO_IN"); ex.setErrorDetails("The pin is asked to go to the state IN while the depth of the r-coordin
MyExceptionClass ex;
ex.setErrorMessage("PIN_CANNOT_GO_IN");
ex.setErrorDetails("The pin is asked to go to the state IN while the depth of the r-coordinate does not support it");
ex.setResolutionMessage("Configure your coordinates-file to move first to the correct position before changing the state of the pin");
ex.VariableList().resize(5);
ex.VariableList()[0].push_back("Pin state: ");
ex.VariableList()[0].push_back(ToString(pin.getPinState()));
ex.VariableList()[1].push_back("Pin target state: ");
ex.VariableList()[1].push_back(ToString(coordinatesData[coordinatesIndex].targetPinState));
ex.VariableList()[2].push_back("Current r Value: ");
ex.VariableList()[2].push_back(ToString(EncoderPosition.r));
ex.VariableList()[3].push_back("Current phi Value: ");
ex.VariableList()[3].push_back(ToString(EncoderPosition.phi));
ex.VariableList()[4].push_back("Current z Value: ");
ex.VariableList()[4].push_back(ToString(EncoderPosition.z));
ex.printLog();
ex.writeLog(exceptionLogFilePath.getValue());
throw ex;
所以只有5个变量,我必须写下所有这些。。。
是否有一种有效的方法来包含程序中的所有信息(至少是变量),而不是每次我想抛出异常时都重写所有这些信息
提前感谢。如果添加到exception类的数据仅用于显示错误消息,则可以使用字符串连接来减少使用的
push_back()
的数量
例如,您可以使用:
ex.VariableList()[0].push_back(string("Pin state: ") + ToString(pin.getPinState());
您甚至可以连接所有其他消息,而不是为每个消息使用单独的索引(1、2、3、4等)
此外,对于每个字段,您可以使用专用的setter方法来提供适当的值。例如:
ex.VariableList()[0].setPinState(ToString(pin.getPinState()));
void MyExceptionClass::setMessage(Pin& pin, CoordinatesData& cd, EncoderPosition& ep) {
setPinState(ToString(pin.getPinState()));
// set whatever else you want here
}
然后将“Pin状态:”
部件移动到打印错误消息的位置
更进一步说,您的异常类可以有一个专用的方法,该方法接受导致错误消息的所有对象,并调用该消息。例如:
ex.VariableList()[0].setPinState(ToString(pin.getPinState()));
void MyExceptionClass::setMessage(Pin& pin, CoordinatesData& cd, EncoderPosition& ep) {
setPinState(ToString(pin.getPinState()));
// set whatever else you want here
}
此外,将ToString()
部分移动到打印消息的任何位置,只需将值存储在exception类中即可。例如,将上面的行更改为(您需要相应地更改签名):
让打印逻辑决定如何将其转换为字符串。另一个优点是,它允许您以不同的格式打印相同的消息。您可以使用一个公共函数(fill_out_exception_parameters)为通用异常填充VariableList对象,并在您编写的任何新异常类中重复使用它。我想我已经找到了最干净的方法。请让我听听你的想法 因此,我将所有相关变量封装在一个模板化类中,如下所示(只是一个简单的示例)
类VarBase
{
VarBase();
静态std::向量uu所有参数;
字符串getStringValue()=0;
};
模板
类变量:公共变量库
{
T值;
字符串名;
字符串描述;
toString();
算子T();
字符串getStringValue();
};
VarBase::VarBase()
{
__所有参数。推回(此);
}
VarBase::~VarBase()
{
//句柄从_allParams向量或任何容器中移除
}
模板
std::string Var::getStringValue()
{
std::strings;
我有一个类似的问题:如何用上下文信息丰富异常
Boost提出了一种解决方案:try/catch
,并在重新刷新之前在catch
块中对异常进行充实。它确实充实了异常,但不会自动进行充实
我最后想出的解决方案非常简单,基于C++析构函数的强度。但是首先,如何使用它:
void foo(int i) {
LOG_EX_VAR(i);
// do something that might throw
}
是的,就是这样,一个宏调用和i
与函数名、文件名和宏展开所在的行号一起添加到异常上下文中
背后是什么?这是一个神奇的故事
class LogVar {
public:
LogVar(LogVar const&) = delete;
LogVar& operator=(LogVar const&) = delete;
virtual ~LogVar() {}
protected:
LogVar();
}; // class LogVar
template <typename T>
class LogVarT: public LogVar {
public:
LogVarT(char const* fc, char const* fl, int l, char const* n, T const& t):
_function(fc), _filename(fl), _line(l), _name(n), _t(t) {}
~LogVar() {
ContextInterface::AddVariable(_function, _filename, _line, _name, _t);
}
private:
char const* _function;
char const* _filename;
int _line;
char const* _name;
T const& _t;
}; // class LogVarT
template <typename T>
LogVarT make_log_var(char const* fc,
char const* fl,
int l,
char const* n,
T const& t)
{
return LogVarT(fc, fl, l, n, t);
}
#define LOG_EX_VAR(Var_) \
LogVar const& BOOST_PP_CAT(_5416454614, Var_) = \
make_log_var(__func__, __FILE__, __LINE__, #Var_, Var_);
最后,最后一个缺失部分(好吧,我想除了您想要的实际上下文之外):一个基本异常类的示例
class ContextualException: public virtual std::exception {
public:
ContextualException(): _c(ContextInterface::SetActive<ExceptionContext>()) {}
ContextInterface const& context() const { return *_c; }
private:
ContextInterface::SPtr _c;
}; // class ContextualException
类上下文异常:公共虚拟std::异常{
公众:
ContextalException():c(ContextInterface::SetActive()){}
ContextInterface常量&context()常量{return*_c;}
私人:
ContextInterface::SPtr\u c;
};//类上下文异常
这些文本描述应该固有地链接到异常类,而不是作为运行时数据写入每个实例
类似地,所有这些信息性数据都应该是exception类的成员,您可以在以后将其格式化为文本输出(可能在exception类本身的成员函数中).您可以使用Boost Exception简化向异常对象添加任意数据的过程,并在它们在调用堆栈中冒泡时使用更多相关数据来扩充它们。您不必担心预先定义可能需要存储在异常中的所有内容,因为您可以根据需要存储任何异常的数据。首先,const用构造函数而不是一堆设置器来构造对象。这就是构造函数的作用。其次,你的异常是一堆字符串,只要将它们格式化为一个大的、用户可呈现的字符串并激发就行了。你是否尝试过编写一个生成异常的函数(即,除了抛出的
行之外,包含所有内容),只需执行抛出exceptionGenerator()
或者您如何调用该函数?该函数如何访问我程序中的变量列表?这意味着我必须通过参数传递它们,然后我们回到原点。是否有方法自动将所有变量添加到我的异常类中?该函数如何访问我程序中的变量列表y程序?这意味着我必须通过参数传递它们,我们回到了第一步。有没有办法让所有变量自动添加到我的异常类?谢谢你的想法。但我仍然在寻找一种更干净的方法,可以自动添加所有变量,我所要做的就是编写错误消息,然后如果您知道我的意思,希望程序自动处理程序中多个点的相同变量名和当前值。@SamerAfach我认为我更新的答案非常接近您的要求。请稍作修改,并让我知道这是否有帮助。:)对该方法的评论?@MatthieuM。谢谢您的回复。为什么我它不是线程安全的吗?只有在创建变量或引发异常时才需要访问向量_allParams,并且您可以使用映射来访问它
class ContextualException: public virtual std::exception {
public:
ContextualException(): _c(ContextInterface::SetActive<ExceptionContext>()) {}
ContextInterface const& context() const { return *_c; }
private:
ContextInterface::SPtr _c;
}; // class ContextualException