13

我喜欢 Python 中找不到正确返回值时可以返回 None 的特性。例如:

def get(self, key):
    if key in self.db:
        return self.db[key]
    return None

我需要在 C++ 中实现相同的功能。我想到了一些可能性。

返回真/假,当真从引用或指针中获取值

bool get(string key, int& result)
{
    if (in(key, db)) {
        result = db[key];
        return true;
    }
    return false;
}

通知 None 情况时抛出错误

int get(string key) throw (int)
{
    if (in(key, db)) {
        result = db[key];
        return result;
    }

    throw 0;
}

try {
    ....
}
catch (int n)
{
    cout << "None";
}

使用对

pair<bool, int> getp(int i)
{
    if (...) {
        return pair<bool, int>(true, 10);
    }
    return pair<bool,int>(false, 20);
}

pair<bool, int> res = getp(10);
if (res.first) {
    cout << res.second;
}

C++中通常使用哪一个?在 C++ 中有没有其他方法可以做到这一点?

4

5 回答 5

17

执行此操作的正常 C++ 方法(注意:C++ 不是 Python)是从此类函数返回迭代器,并end()在找不到项目时返回。

但是,如果您希望使用非迭代器返回值,boost::optionalboost::none在返回 Python 的None.

throw除非您希望在正常执行期间永远不会出现错误情况,否则绝对不要使用。

于 2013-06-13T23:05:52.397 回答
3

Checked我使用一个小的自定义模板类实现了好/坏的返回值。我的实际课程更全面一些,包括赋值运算符、错误原因字符串和引用类型的特化等,这就是我没有使用boost::optional<T>. 如果有兴趣,我可以发布完整的课程。

该课程的一般要点是:

static const class Bad {} None;

template<typename ValueType>
class Checked
{
public:
    // Constructor for good value.
    Checked(ValueType x)
        : value(x), valid(true)
    {}

    // Constructor for bad value.
    Checked(Bad)
        : value(), valid(false)
    {}

    operator ValueType(void) const
    {
        if (!valid)
            ;//assert or throw...

        return value;
    }

    ValueType value;
    bool valid;
};

这可以像这样使用:

Checked<int> Divide(int numerator, int denominator)
{
    if (denominator == 0)
        return Bad(); // or None;

    return numerator / denominator; // Automatically uses the "good value" constructor
}

或者:

Checked<int> result = Divide(4, 5);
if (result.valid)
    std::cout << result; // or result.value
else
    std::cout << "Bad!";

由于返回值优化,这种方法通常比参考方法更有效。

于 2013-06-14T00:01:08.353 回答
1

我认为 C++ 中的不同项目使用不同的标准,但是您提到的Return true/false可能是 C++ 中最常见的方式,尽管有些人更喜欢在成功时返回 false,而其他人则在成功时返回 true。在其他情况下,如果您要获取的值是指针,则返回 null 是 C++ 中的另一种常见方式。

例如,如果你在做微软相关的项目,那么最常见的方法是返回HRESULT,这是微软引入的一种返回类型。

在 linux 中,函数通常在成功时返回 0,非零值表示错误代码。(您可能会发现此讨论很有帮助)。

于 2013-06-13T23:03:53.517 回答
1

返回指针时,我可以使用 reinterpret_cast 进行 NULL 返回。

class A
{
};

A* a(int i)
{
    if (i == 0) return new A();
    return reinterpret_cast<A*>(NULL);
}
int main(int argc, char *argv[]) {
    A* result = a(1); // result is NULL
    if (result == NULL) {
        cout << "NULL returned";
    }
    result = a(0);
    if (result != NULL) {
        cout << "NON NULL returned";
    }
}
于 2013-06-18T14:43:22.163 回答
1

我想说这三种方法在 C++ 中都很常见。

不用说,如果返回类型已经可以具有某种“无效”或“僵尸”状态(例如,像NULL指针或NaN数字),那么这可能是最容易使用的东西。

“通过引用获取输出参数并返回错误代码”是更传统的 C 风格的做事方式,当然,这很常见。传统是在成功时返回 0,在失败时返回一些错误代码(任何非零值)。

如果您在代码中采用异常,则“如果无法返回值则抛出异常”通常是有意义的。这很常见,但并未被普遍接受(并非每个人都喜欢或出于相同目的使用异常)。

前两个选项是永无止境的争执(即错误代码与异常),这实际上取决于您选择哪一方。因此,我建议您参考那场辩论(当然,这对于 StackOverflow 来说太主观了)。

我想说, “返回一对bool和价值”不太常见,但我仍然见过很多次。随着元组(boost::tuplestd::tuple(C++11))的采用和层(boost::tiestd::tie(C++11))的使用,从函数返回多个值的整个想法(就像许多语言允许的那样)变得更具吸引力并在实践中使用。

在其他选项中,您有boost::optional<T>,其名称非常不言自明(基本上,第三个选项(对)包装在一个更漂亮的包中)。而且您可能还拥有 Alexandrescu 的 Expected 模板,它为您提供了所有三个选项的混合,以便您获得一个与标志捆绑在一起的返回值,以了解它是否有效,并与描述为什么它不能产生的异常捆绑在一起该值,如果您尝试读取无效值,将自动抛出该值。但是,该模板需要 C++11 功能才能工作。

于 2013-06-13T23:29:07.020 回答