构造函数应该如何报告错误?指向外部标志的指针
How should a constructor report errors? Pointers to external flags?
我正在重构一些旧的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;
}
虽然我已经能够使用类似于这种方法的东西,但我不知道它是否可移植。
这是正确的事情吗?
如果没有,我是否只是使用指针来初始化类,而不是通过引用传递错误消息变量?或者我还能做些什么?
我不能使用异常在当前阶段,因为有许多函数调用/从外部代码使用"返回错误消息"的方法仍然。
如果可能的话,您应该修复调用代码,以便可以处理异常,您可以使用两阶段构造习惯:
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
,你可以删除它。
你的代码是危险的,因为它允许这样的坏用例:
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文章,你应该把理解它们作为一个c++开发人员的目标。
编写新代码以正确使用异常。当你遇到新旧代码之间的边界时,转换错误类型
顺便说一下,异常是构造函数失败的的合理方式。这都是RAII的一部分,而RAII是使c++如此强大的关键。构造函数建立你的不变量,而异常标志着不能满足后置条件——把它们放在一起,这里是重要的哲学:在c++中只有有效的对象应该存在,如果你通过利用RAII正确地做到了这一点,那么对象的持续存在就是程序有效性的证明。我不能在当前阶段使用异常,因为有很多函数调用使用"返回错误"的外部代码消息"接近仍在。
然后先解决这个问题。然后使用异常
- 在函数内部的声明中初始化数组,并在外部使用它
- 使外部项目可用于find_package CMake
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- 使用外部SDK工具链文件在VisualStudio上生成项目编译错误
- C++:来自外部文件的Trivia
- 从函数角度看ID到文件路径的内部与外部映射
- C++:将外部库链接到dll库
- spdlog标头仅与外部fmt一起使用.spdlog错误:'内部':不是'fmt'
- 节俭并发:未解决的外部问题
- 如何在c++中从git建立外部库
- 未解析的外部符号_MsiLocateComponentW@12.
- 如何使用对C函数和类对象的外部调用来处理C++头文件
- 即使使用调试编译标志,表达式也是"optimized out"
- 具有外部"c"和程序集的未定义函数
- 在 CMake 中为每个目标设置编译器/链接器标志
- 为什么导入Mixed native/CLR lib.dll的本机C++应用程序没有在Mixed lib.dll中的外部变
- C++编译器标志忽略外部库的警告,但不包括目录
- 针对外部标志(cpp)的循环条件的更改
- 如何在没有外部标志的情况下只在循环中运行一次代码
- 构造函数应该如何报告错误?指向外部标志的指针