构造函数应该如何报告错误?指向外部标志的指针?
我正在努力重构一些旧的 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;
}
虽然我已经能够使用与此方法类似的方法,但我不知道这是否会是便携的。
这是正确的做法吗?
如果不是,我是否只使用指针来初始化类,而不是通过引用传递错误消息变量?或者还有什么我可以做的吗?
我在当前阶段无法使用异常,因为有许多对外部代码的函数调用仍然使用“返回错误消息”方法。
I am working on refactoring some of the old C-style code to bring it more into line with C++ code. I still am a bit new to C++
An example of the code I am working on is as follows
Errmsg foo{
ErrMsg err = NoError;
/*
Some Processing
*/
err = foo_cleanup(err,/* some parameters*/);
/*
Some More Processing
*/
return err;
}
I was thinking of developing a class so that
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;
}
Although I have been able to use something similar to this approach, I do not know if this will be portable.
Is this the right thing to do?
If not, do I just use pointers to initialize the class instead of passing the error message variable by reference? Or is there something else I can do?
I cannot use exceptions at the current stage because there are many function calls to/from external code which use a "return error message" approach still.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
暂且不说,如果可能的话,您应该修复调用代码,以便异常正常,您可以使用两阶段构造惯用法:
现在,使用异常的代码可以调用多参数构造函数(并在准备就绪的情况下获取对象) to-use 状态),而异常厌恶代码可以调用默认构造函数,后跟
nothrow_init
(并且接受这样的事实:如果nothrow_init
失败,它们的对象上就会有一个不可用的对象手,这是他们的确保他们不使用它的责任)。将来,当您将代码库的其他部分带入异常使用状态时,您会发现
init
中的代码调用本身可以抛出的东西。此时,您可以开始移动代码,以便nothrow_init
调用可以抛出异常的init
函数,但捕获任何异常并将其转换为错误代码。假设它是一个内部类,那么最终什么都不会使用nothrow_init
并且您可以将其删除。Leaving aside that you should if possible fix the calling code so that an exception is OK, you could use the two-phase construction idiom:
Now, exception-using code can call the multi-arg constructor (and get the object in a ready-to-use state), whereas exception-averse code can call the default constructor followed by
nothrow_init
(and live with the fact that ifnothrow_init
fails they have an unusable object on their hands, and it's their responsibility to ensure that they don't use it).In future, as you bring other parts of your code base into an exception-using state, you will find that the code in
init
calls things that can themselves throw. At that point you can start moving code around, so that thenothrow_init
calls aninit
function that can throw, but catches any exceptions and turns them into error codes. Assuming it's an internal class then eventually nothing will be usingnothrow_init
and you can remove it.您的代码很危险,因为它允许出现如下不良用例:
不要尝试使用返回代码来表示构造函数失败。 你不能。使用异常。
您可以将异常包装在返回代码中,反之亦然。
例外很重要。有很多好的 GOTW 文章,您应该将理解它们作为成为 C++ 的目标开发商。
编写新代码以正确使用异常。每当遇到新旧代码之间的界限时,请转换错误类型。
顺便说一句,异常是构造函数失败的唯一合理方式。这些都是 RAII 的一部分,而 RAII 是使 C++ 如此强大的关键。构造函数建立不变量和异常,表明无法满足后置条件 - 将它们放在一起,这里是重要的哲学:在 C++ 中只有有效对象应该存在,如果你得到通过利用 RAII 的这种权利,那么对象的持续存在就是程序有效性的证明。
Your code is dangerous because it permits bad use-cases such as this:
Don't try to signal constructor failures with return codes. You can't. Use exceptions.
You can wrap exceptions in return codes and vice-versa.
Exceptions are important. There are lots of good GOTW articles and you should make understanding them a goal in being a C++ developer.
Write the new code to use exceptions properly. Convert error types whenever you hit a boundry between old and new code.
By the way, exceptions are the only reasonable way for a constructor to fail. It's all part of RAII which is a key to making C++ so powerful. Constructors establish your invariants and exceptions signal a failure to satisfy postconditions -- put it all together and here is the important philosophy: in C++ only valid objects should exist, if you get this right by exploiting RAII then the continued existence of an object is proof of the program's validity.
然后先解决该问题。然后使用异常。
Then fix that problem first. Then use exceptions.