c++ - c++,处理来自构造函数的异常
问题描述
我有一个从外部文件加载的类,所以理想情况下,如果加载失败,我希望它的构造函数从给定路径加载,如果找不到/不可读文件,我会抛出错误(从构造函数不是一个可怕的想法,请参阅ISO 的常见问题解答)。
但是,这有一个问题,我想以某种受控方式自己处理错误,并且我想立即执行此操作,因此我需要在该对象的构造函数周围放置一个 try-catch 语句……如果我这样做了也就是说,该对象未在 try 语句之外声明,即:
//in my_class.hpp
class my_class
{
...
public:
my_class(string path);//Throws file not found, or other error error
...
};
//anywhere my_class is needed
try
{
my_class my_object(string);
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
//Problem... now my_object doesn't exist anymore
我已经尝试了很多方法来解决它,但我真的不喜欢其中任何一种:
首先,我可以使用指向 my_class 的指针而不是类本身:
my_class* my_pointer;
try
{
my_class my_pointer = new my_class(string);
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
问题是这个对象的实例并不总是在创建它的同一个对象中结束,所以正确删除所有指针很容易出错,此外,我个人认为让一些对象成为指针很难看对象,并让大多数其他对象成为“常规对象”。
其次,我可以以几乎相同的方式使用只有一个元素的向量:
std::vector<my_class> single_vector;
try
{
single_vector.push_back(my_class(string));
single_vector.shrink_to_fit();
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
我不喜欢有很多单元素向量的想法。
第三,我可以创建一个空的仿构造函数并使用另一个加载函数,即
//in my_class.hpp
class my_class
{
...
public:
my_class() {}// Faux constructor which does nothing
void load(string path);//All the code in the constructor has been moved here
...
};
//anywhere my_class is needed
my_class my_object
try
{
my_object.load(path);
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
这行得通,但在很大程度上违背了拥有构造函数的目的,所以我也不是很喜欢这个。
所以我的问题是,在这些构造对象的方法中,哪些可能会在构造函数中引发错误,是最好的(或最不坏的)?有没有更好的方法来做到这一点?
编辑:你为什么不直接使用 try 语句中的对象
因为该对象可能需要在程序第一次启动时创建,并在很久以后停止。在最极端的情况下(在这种情况下我也确实需要),基本上是:
int main()
{
try
{
//... things which might fail
//A few hundred lines of code
}
catch(/*whaveter*/)
{
}
}
我认为这使我的代码难以阅读,因为 catch 语句与实际出错的地方相去甚远。
解决方案
一种可能性是将构造和错误处理包装在一个函数中,返回构造的对象。例子 :
#include <string>
class my_class {
public:
my_class(std::string path);
};
my_class make_my_object(std::string path)
{
try {
return {std::move(path)};
}
catch(...) {
// Handle however you want
}
}
int main()
{
auto my_object = make_my_object("this path doesn't exist");
}
但请注意,该示例是不完整的,因为不清楚当构造失败时您打算做什么。该catch
块必须要么返回一些东西,要么抛出或终止。
my_class(std::string path)
如果您可以返回一个不同的实例,一个具有“错误”或“默认”状态的实例,那么您可以在确定路径无效时将您的实例初始化为该状态。因此,在这种情况下,不需要try
/块。catch
- 如果您重新抛出异常,那么首先捕获它是没有意义的。在这种情况下,也不需要
try
/块,除非你想做一些额外的工作,比如日志记录。catch
- 如果你想终止,你可以让异常不被捕获。同样,在这种情况下,不需要
try
/块。catch
这里真正的解决方案可能是根本不使用try
/catch
块,除非实际上存在错误处理,否则您不应该将其实现为my_class
问题中不明显的部分(可能是回退路径?)。
推荐阅读
- here-api - 使用 here-api 查找门牌号为 17 1/2 的地址
- python - AttributeError: 'NoneType' object has no attribute 'send' ,当我尝试将带有机器人的消息发送到特定的不和谐频道时
- pine-script - 回测 - 如果在上一次收盘和新交易之间没有发生条件,则不开仓
- javascript - MongoDB 使用聚合管道计算单个用户的所有喜欢和帖子
- uncertainty - 执行不确定性 - 蒙特卡罗分析 - 在 Brightway2 中使用 Ecoinvent
- javascript - 链接没有返回值的承诺的最佳实践
- html - CSS 布局 - 网格或弹性
- ringcentral - 在来电时打开网页
- javascript - YTDL-Core 错误:输入流:未找到视频 ID:l
- php - 如何更改消息:上传的文件超过了 php.ini 中的 upload_max_filesize 指令