我正在努力重构一些旧的C风格代码,使其更符合C ++代码。我对C ++还有点新鲜
我正在处理的代码示例如下
Errmsg foo{
ErrMsg err = NoError;
/*
Some Processing
*/
err = foo_cleanup(err,/* some parameters*/);
/*
Some More Processing
*/
return err;
}
我正在考虑开发一个类,以便
class foo_class
{
public:
foo_class(Errmsg errmsg_init&,/*Some other arguments */ ):
errmsg(&errmsg_init),
/*Initialize other parameters */{}
void foo_cleanup (/*Other parameters*/);
// same functionality, but since the source variable is available,
// it can be modified without having to return any variable
~foo_class(){foo_cleanup(/*Parameters*/);}
/*
Member functions
*/
private:
Errmsg* errmsg;
/*Some other parameters */
};
Errmsg foo{
ErrMsg err = NoError;
foo_class foo_obj(err);
/*
Some Processing
*/
// The class would be
//cleaned up before returning
// and the err variable would be
//modified in the destructor
return err;
}
虽然我已经能够使用类似于这种方法的东西,但我不知道这是否可以移植。
这是正确的做法吗?
如果没有,我是否只使用指针初始化类而不是通过引用传递错误消息变量?或者我还能做些什么吗?
我不能在当前阶段使用异常,因为有许多来自/来自外部代码的函数调用仍使用“返回错误消息”方法。
答案 0 :(得分:1)
您的代码很危险,因为它允许使用错误的用例:
return new FooClass (local_error_code_variable);
不要尝试使用返回码来表示构造函数失败。 你不能。使用例外。
您可以在返回代码中包含异常,反之亦然。
class NewAPIClass {
NewAPIClass () {
error_code err = old_api_function ();
if (OLD_API_OK != err)
throw NewAPIException (err);
}
}
extern "C" error_code new_api_callback_function (argument arg) {
try {
NewAPIClass object;
object .do_work ();
}
catch (...) {
return OLD_API_ERROR;
}
}
int main () {
old_api_install_callback (new_api_callback_function);
}
例外非常重要。有许多好的GOTW articles,你应该把它们理解为成为C ++开发人员的目标。
编写新代码以正确使用异常。无论何时遇到旧代码和新代码之间的边界,都要转换错误类型。
顺便说一句,例外是 唯一 构造函数失败的合理方式。这是RAII的一部分,这是使C ++如此强大的关键。构造函数建立不变量和异常表示无法满足后置条件 - 将它们放在一起这就是重要的哲学: 在C ++中只有有效对象存在 ,如果你得到的话通过利用RAII这一权利,对象的继续存在就证明了程序的有效性。
答案 1 :(得分:1)
暂且不说,如果可能的话,你应该修改调用代码以便异常正常,你可以使用两阶段构造习语:
struct foo_class {
foo_class() { } // default constructor cannot fail
Errmsg nothrow_init(/* other params */) throw() {
/* initialize other parameters */
}
foo_class(/* other params */) {
if (nothrow_init(/* other params */) != ERRMSG_OK) {
throw something;
}
}
};
现在,异常使用代码可以调用multi-arg构造函数(并使对象处于准备使用状态),而异常代码可以调用默认构造函数,后跟nothrow_init
(和如果nothrow_init
失败,他们手上就有一个无法使用的物体,他们有责任确保他们不使用它。
将来,当你将代码库的其他部分带入异常使用状态时,你会发现init
中的代码会调用自己可以抛出的东西。此时,您可以开始移动代码,以便nothrow_init
调用可以抛出的init
函数,但捕获任何异常并将其转换为错误代码。假设它是一个内部类,那么最终什么都不会使用nothrow_init
,你可以删除它。
答案 2 :(得分:0)
我不能在当前阶段使用例外,因为有很多例外 函数调用/从外部代码调用使用“返回错误 消息“接近。”
然后先解决这个问题。然后使用例外。