构造函数应该如何报告错误?指向外部标志的指针?
Posted
技术标签:
【中文标题】构造函数应该如何报告错误?指向外部标志的指针?【英文标题】:How should a constructor report errors? Pointers to external flags? 【发布时间】:2011-09-12 14:10:22 【问题描述】:我正在重构一些旧的 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;
虽然我已经能够使用类似于这种方法的东西,但我不知道这是否可以移植。
这是正确的做法吗?
如果不是,我是否只使用指针来初始化类而不是通过引用传递错误消息变量?或者还有什么我可以做的吗?
在当前阶段我不能使用异常,因为外部代码的许多函数调用仍然使用“返回错误消息”方法。
【问题讨论】:
【参考方案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;
;
现在,使用异常的代码可以调用多参数构造函数(并使对象处于准备使用状态),而厌恶异常的代码可以调用默认构造函数,后跟nothrow_init
(并与事实上,如果nothrow_init
失败,他们手上有一个无法使用的对象,他们有责任确保他们不使用它)。
将来,当您将代码库的其他部分带入异常使用状态时,您会发现init
中的代码调用了可以自己抛出的东西。此时您可以开始移动代码,以便nothrow_init
调用可以抛出但捕获任何异常并将它们转换为错误代码的init
函数。假设它是一个内部类,那么最终什么都不会使用nothrow_init
,您可以将其删除。
【讨论】:
【参考方案2】:您的代码很危险,因为它允许出现以下不良用例:
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 获得此权利,那么对象的持续存在就是程序有效性的证明。
【讨论】:
【参考方案3】:我不能在当前阶段使用异常,因为有很多 使用“返回错误”的外部代码的函数调用 消息”方法仍然存在。
然后先解决这个问题。然后使用异常。
【讨论】:
-1 因为...很多东西。例外是一种工具。说无视一切并锤炼你的信念,你应该如何编程是另一回事。一句话回复很少有用。异常作为控制流??等等……等等……请扩展你的推理,我会投票并说我错了。 查看我的答案和链接的 GOTW。例外并不适用于所有情况,但对于它们所适用的情况,有 NO 有效的替代方案。失败的对象构造就是其中之一。 在构造函数中不做更适合流控制的事情怎么样。有时在那里做这些事情是完全有效的。这显然不是这种情况。真的,如果有机会,你们会抛出 CHeyWeJustAddedANumberException :P 我不知道你在说什么。我没有提倡将异常作为控制流,也没有展示任何其他 OTT 提倡的异常。然而,异常对于发出错误信号非常有用,并且比返回码要好得多,应该改为使用。以上是关于构造函数应该如何报告错误?指向外部标志的指针?的主要内容,如果未能解决你的问题,请参考以下文章