如何从C++函数返回多个错误代码

4

什么是从C++函数返回成功或一个或多个错误代码的好方法?

我有一个名为save()的成员函数,它将每个成员变量保存到其中,至少有十个这样的成员变量需要保存,对于调用save()函数,我想知道调用是否失败,如果失败,则在哪个成员变量上(有些是硬性失败,有些是软性失败)。


为什么需要提供多个错误代码?也许如果您提供有关此类函数的使用模式、多个错误代码的原因或其他信息,那么可能会有更好的解决方案。 - Lasse V. Karlsen
我有一个名为save()的成员函数,它保存到每个成员变量中,至少有十个这样的成员变量需要保存。对于调用save(),我想找出是否调用失败,如果失败了,是在哪个成员变量上(有些是硬性失败,有些是软性失败)。 - bob
9个回答

7
你可以返回一个具有多个错误字段的对象,也可以使用'out'参数。
如何实现取决于你的设计和你要返回的内容。常见情况是需要报告状态码以及类似消息的信息。有时候函数会将状态码作为返回值返回,然后通过'out'参数返回消息状态。
如果你只是返回一组'代码',那么构造一个结构体类型并返回可能更有意义。在这种情况下,我倾向于将其作为输出参数传递,并让方法内部更新它,而不是每次都分配一个新的。
你打算做一次还是多次?

对象是一个不错的解决方案,因为你可以返回任何你想要的东西,例如错误代码,错误字符串等。 - Soo Wei Tan

6

我通常使用 boost::tuple

typedef boost::tuple<int,int> return_value;

return_value r = my_function();

int first_value = boost::get<0>( r );
int second_valud = boost::get<1>( r );

编辑

你也可以使用 boost::tie 从元组中提取值:

boost::tie( first_value, second_value ) = r;

1
您可以使用 tiers 来取消 touple 的分组:http://www.boost.org/doc/libs/1_39_0/libs/tuple/doc/tuple_users_guide.html#tiers - Martin York

6
我知道这并不是你问题的答案,但是...
在C ++中,应该使用异常而不是返回错误代码。 错误代码通常由不想强制库用户使用特定错误处理约定的库使用,但在C ++中,我们已经有了stdexcept。当然,可能有理由不使用异常,例如如果你正在编写嵌入式代码或内核扩展。

4
虽然我没有反对使用异常,但有时使用错误代码会更好。我认为说你“应该使用”异常有些过头了。 - David Thornley
而异常类可以作为属性携带OP所要求的所有详细信息。 - lothar
1
当错误的上下文提供的信息不足以处理问题时,异常是非常有用的。通过使用异常,您可以将错误处理转移到更高级别,并获得更多的上下文。但是,如果您在当前级别拥有足够的上下文,则错误代码是可以接受并且也更可取的,而不是异常。 - Martin York
1
请参见:https://dev59.com/DHVD5IYBdhLWcg3wDXF3#106749,了解更多关于何时使用异常的评论。 - Martin York
我同意这个答案的观点 - 异常通常应该首先考虑,并且只有在有充分理由的情况下才应该被拒绝,这也是作者在他的回答中所提到的。使用异常通常会导致更清晰、更易于维护的代码。 - markh44
@markh44:我同意对于公共方法。对于私有方法,我会反转逻辑(但仅限于遵循我上面解释的逻辑)。 - Martin York

4
最简单的返回两个值的方法是使用 std::pair<> 模板:

3

如果您的意图纯粹是返回错误状态,我建议使用bitset

const bitset<10> a_not_set(1);
const bitset<10> b_not_set(2);
const bitset<10> c_not_set(4);

...

bitset<10> foo(T& a, T& b, T& c, ...)
{

    bitset<10> error_code = 0;

    ...


    if ( /* a can't be set */ )
    {
        error_code |= a_not_set;
    }

    ...

    if ( /* b can't be set */ )
    {
        error_code |= b_not_set;
    }

    ...

    // etc etc

    return error_code;
}

bitset<10> err = foo(a, b, c, ... );
if (err && a_not_set)
{
   // Blah.
}

2
你需要将它们作为输出参数返回:
 bool function(int& error1, int& error2, stringx& errorText, int& error3);

2

我可能会首先尝试抛出异常,但这取决于你的编程范式。请参考一些关于为什么C++异常处理可能更好的书籍或文章。

如果我确实需要坚持返回错误代码的风格,我将使用位操作定义一个枚举类型来指定错误。

enum error
{
   NO_ERROR = 0,

   MEMBER_0_NOT_SAVED = 1,
   MEMBER_1_NOT_SAVED = 1 << 1,
   MEMBER_2_NOT_SAVED = 1 << 2,
   // etc..

};

int save()
{
    int ret = NO_ERROR;

    // fail to save member_0
    ret  |= MEMBER_0_NOT_SAVED;

    // fail to save member_1
    ret  |= MEMBER_1_NOT_SAVED;

    // ....

    return ret; 
}

int main(void)
{
    int ret = save();
    if( ret == NO_ERROR)
    {
       // good.
    }
    else
    {
        if(ret & MEMBER_0_NOT_SAVED)
        {
              // do something
        }

        if(ret & MEMBER_1_NOT_SAVED)
        {
              // do something
        }

        // check the other errors...
    }
}

这只是一个简单的例子。最好将其放入类中或使用命名空间。


2

您可以使用整数和位运算(也称为标志)。


+1 好主意,对于错误数量有限的情况,也许您可以通过一些代码来扩展您的答案... - Daniel Wedlund
为了解决可读性问题,您可以始终使用位域。它为每个标志提供名称,允许使用“正常”的布尔运算符而不是位移运算符,并且占用与 int 相同的空间。 - Max Lybbert
这是专业的方法,实现它不需要任何 CPU 时间成本。 - toto

0

我不熟悉您的项目内部和限制,但如果可能的话,请尝试使用异常而不是错误代码。

原因在这里,在C++ FAQ lite中列出,并得出以下结论:

因此,与通过返回代码和if进行错误报告相比,使用try / catch / throw很可能会导致具有更少错误、开发成本更低且上市时间更快的代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接