此问题的简短版本是如何实现同时返回true
和false
的单个函数,同时在失败时提供详细信息(false
)?
假设我想创建静态函数remove()
,它将获得string
的路径并将其从文件系统中删除。
假设删除操作可能会导致一些意外错误,我希望能够返回状态。
版本1
static bool remove( const string& path );
如果删除了路径,则会返回true
,否则会返回false
但是,如果我需要有关删除过程失败的更多详细信息,该怎么办?
版本2
static void remove( const string& path );
此功能现在抛出一些exception
失败,这基本上会返回删除进程失败的原因。这要求每个调用者在调用此函数时使用try-catch
,如果您不关心结果,这可能有点烦人和丑陋。
我试图生成一个干净的签名,允许我将两个版本合并为一个版本
remove
函数只是众多静态实用函数中的一个,所以我想避免不得不同时离开这两个版本(即使它们目前无法覆盖)。
建议1:
static bool remove( const string& path, bool throw_on_fail );
现在调用者可以通过传递布尔标志来替换函数的两个版本
我不喜欢这个建议。正如我所说remove
函数只是众多静态实用函数中的一个。我不认为为每个函数添加布尔参数是个好主意。
建议2:
static EResultCode remove( const string& path );
此处我们有enum
作为结果
这个有点好,但我已经可以看到下一个if
语句if remove("f1")
这样的错误。从remove()
获取int值4并不意味着成功。
建议3:
static Result remove( const string& path );
这里我们有一个类Result
,它将包含布尔和详细描述
这似乎对我来说太过分了。
我查看了常见c++
库界面的API,wx& boost。在那里找不到压倒性的见解。
我正在尝试为所有这些功能提供通用签名。你会走哪条路?
答案 0 :(得分:2)
struct status {
std::string msg;
bool success;
status(): success(true) {}
status(std::string msg_): success(false), msg(msg_) {}
explicit operator bool() const { return success; }
};
static status const success;
status func1() { return true; }
status func2() { return success; }
status func3() { return status("something went wrong); }
if (func1()) { std::cout << "success!" << std::endl; }
if (func1().success) { std::cout << "success!" << std::endl; }
auto rc = func3();
if (!rc) { std::cout << "error" << rc.msg << std::endl; }
答案 1 :(得分:2)
我肯定会使用Result类方法。
忽略异常是否是首先处理文件未找到错误的正确工具的问题,启用或禁用它们的额外bool参数将使得客户端代码因为所有的true和false参数而不易读取除非读者参考remove()的文档或至少其签名,否则其含义完全不清楚:
remove("file.txt", true); // what's true?!
我也会避免错误引用。当您(函数的客户端)被迫使用您以后可能不需要的其他局部变量时,这是非常令人沮丧的。非常C ++ - 不像。这种方法最终会产生很多像这样的客户端代码:
Error dummy;
remove("file.txt", dummy);
Result类方法意味着客户端必须输入更多,如果他们需要知道错误的详细信息,但由于它们的代码将变得更加清晰和可读。您担心这会给客户带来额外的负担似乎毫无根据,至少如果我把自己想象成remove()的客户那样:)
答案 2 :(得分:1)
如果你有一个函数remove()
,并且函数的目的是从文件系统中删除东西,我们应该期望它在正常情况下工作。
如果由于某种原因无法工作(有很多原因可能会失败),我们应该将其视为正常工作案例的例外。
我建议:
void remove() {...}
并称之为:
try
{
remove("/home/olduser");
}
catch(std::runtime_error& e)
{
std::cerr << "Failed to remove: " << e.what() << '\n';
}
例外情况是语言的一部分,使用它们。
你说你向boost
(以及其他人)寻求灵感。看看boost::asio
的实现。几乎所有的函数都有两个重载,一个用于将报告到中的错误代码,另一个具有相同的行为,但只是在失败的情况下将错误代码作为异常抛出。 / p>
提供两者可能有点矫枉过正。我倾向于依赖异常处理,因为它是专门为处理这些类型的情况而设计的。
答案 3 :(得分:1)
我在一个案例中做的是让函数返回char
const*
,成功nullptr
,并显示错误消息
失败。在这种情况下,函数仍为extern "C"
,
所以我没有多少替代品。在C ++中,我会
可能定义一个类,并返回它。这堂课可以有一个
如果你愿意,隐式转换为bool
,但我不是
确信这是个好主意;我有一个succeeded
功能
返回bool
:它更加清晰。
请注意,即使在这种情况下,您也必须存储退货 将值转换为局部变量,以便具有附加值 在您检测到故障后仍然存在信息;您 不能简单地写:
if ( remove( path ) ) {
// error
} else {
// success
}
但需要写:
Results results = remove( path );
if ( !results ) {
// error, do something with results.message()
} else {
// success
}
也很痛苦,差不多就像尝试一样。
答案 4 :(得分:0)
您可以使用类似
的内容static bool remove( const string& path, tStatus& myStatus );
将tStatus定义为您想要返回错误的任何类型。可以像typedef int tStatus;
答案 5 :(得分:0)
您也可以让函数返回bool,并在参数中传递对可能包含原因的结构的引用。像这样:
bool remove(const string& path, FailReason* fr){
//if the FailReason is a null pointer we don't fill it
If(fr != 0);
}
您可以在失败结构中传递null
答案 6 :(得分:0)
您可以使用:
static bool remove(const string& path, std::nothrow_t);
static void remove(const string& path);