在实用程序类文件中,我想打开一个文件以进行读取或写入。
如果无法打开它,我不想继续该过程。
FileUtility::FileUtility(const char *fileName) {
ifstream in_stream;
in_stream.open(filename);
}
FileUtility fu = FileUtility("bob.txt");
fu.read();
fu.write();
文件bob.txt
不存在,所以我不想读取和写入方法。
有没有一种干净的方法可以做到这一点?
通常,有四种方法可以将错误状态从被呼叫者传达给呼叫者:
1.直接返回值(返回码或OUT参数)。
尽管可以使用OUT参数,但对于构造函数调用而言,返回码是不可能的。但是,为此目的要求每个函数提供其返回代码或OUT参数在某种程度上具有侵入性,因此,尽管肯定在各种库和API中大量使用了此解决方案,但我总体上并不喜欢该解决方案。您可以通过向构造函数添加指针或引用参数来使用此方法,调用者可以向该指针或引用参数提供一些局部错误变量的地址,构造函数可以在其中存储可能的返回值。我不建议这样做。
2.例外。
在C ++代码和其他语言中,关于异常的优缺点的争论有些两极化。我可能会这样说,但我个人认为应该避免像瘟疫一样避免例外。请访问http://www.joelonsoftware.com/items/2003/10/13.html,以了解支持我观点的人。但是,如果您愿意的话,这是一个可行的解决方案。有关此解决方案的良好演示,请参见@Brian的答案。
3.对象属性。
该std::ifstream
对象实际上是这样做的,因此您可以利用它。(实际上,从您的示例代码中,您将您定义std::ifstream
为构造函数中的局部变量,这意味着该变量在调用后将不会持久化,但是由于您在构造对象上调用了某种read()
和write()
方法,这意味着您确实可以持久调用之后,因此我将假设后者是正确的推断。)您可以通过调用来利用它std::ifstream::is_open()
。如果您要维护的封装,则std::ifstream
可以定义自己的is_open()
等效项,并假设它保留为类的一个属性FileUtility
,则将in_stream.is_open();
再次简单地返回FileUtility
。
struct FileUtility {
ifstream ifs;
FileUtility(const char* fileName);
bool is_open(void) const;
};
FileUtility::FileUtility(const char* fileName) { ifs.open(fileName); }
bool FileUtility::is_open(void) const { return ifs.is_open(); }
FileUtility fu = FileUtility("bob.txt");
if (!fu.is_open()) return 1;
或者,您可以仅为FileUtility
该类创建一个全新的错误状态层,然后std::ifstream
通过该层传播错误。例如:
struct FileUtility {
static const int ERROR_NONE = 0;
static const int ERROR_BADFILE = 1;
ifstream ifs;
int error;
FileUtility(const char* fileName);
};
FileUtility::FileUtility(const char* fileName) : error(ERROR_NONE) {
ifs.open(fileName);
if (!ifs.is_open()) { error = ERROR_BADFILE; return; }
}
FileUtility fu = FileUtility("bob.txt");
if (fu.error != FileUtility::ERROR_NONE) return 1;
这些是合理的解决方案。
4.全局错误状态。
如果某些程序员对这种可能的解决方案做出“听起来像个坏主意”的反应,我不会感到惊讶,但事实是,许多非常成功且杰出的代码库都使用这种解决方案来传达错误状态。最好的例子也许是errno
C标准库使用的变量(尽管应该指出,errno
这种工作与直接返回代码结合使用)以及GetLastError()
Windows C API使用的系统。我想有些人可能会认为这确实是“ C方法”,而例外就是“ C ++方法”,但是同样,我避免了像瘟疫这样的例外。
顺便说一句,multithreadedness是不是该解决的问题,因为errno
和GetLastError()
这两个线程局部错误状态,而不是真正的全局错误状态。
我最喜欢此解决方案,因为它简单,极具侵略性,并且可以轻松地被不同的代码库重用,当然,前提是您可以ERROR_NONE
在它自己的库,在这种情况下,您的代码在错误处理方面会获得一致性。
例子:
#define ERROR_NONE 0
thread_local int error = ERROR_NONE;
struct FileUtility {
static const int ERROR_BADFILE = 1;
ifstream ifs;
FileUtility(const char* fileName);
};
FileUtility::FileUtility(const char* fileName) {
ifs.open(fileName);
if (!ifs.is_open()) { error = ERROR_BADFILE; return; }
}
FileUtility fu = FileUtility("bob.txt");
if (error != ERROR_NONE) return 1;
这是我建议的解决方案。否则,我将使用对象属性解决方案。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句