创建函数签名,返回true和false,同时在失败时提供详细信息

时间:2014-02-20 15:28:39

标签: c++ return-value

此问题的简短版本是如何实现同时返回truefalse的单个函数,同时在失败时提供详细信息(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。在那里找不到压倒性的见解。

我正在尝试为所有这些功能提供通用签名。你会走哪条路?

7 个答案:

答案 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);