返回迭代器时,最好返回迭代器类型或实际对象

时间:2015-10-27 19:03:46

标签: c++ iterator

在我的下面的代码中,在哈希表中查找一个值,如果在地图中找不到该键,我会感到困惑。

返回迭代器是否更好,以便调用者可以检查它?

提出异常会更好吗?

或者做点什么?

以下是代码:

#include <vector>
#include <algorithm>
#include <string>
#include <unordered_map>

struct binary_message
{
    binary_message(std::initializer_list<unsigned char> data) : bytes_(data) {}
    std::vector<unsigned char> bytes_;
};


// warning C4715: 'lookup_msg' : not all control paths return a value
static const binary_message& lookup_msg(const std::string& key) {
    static std::unordered_map<std::string, binary_message> table =
    {
        { "msg1", { 0x60, 0x23, 0x80, 0x02, 0x07, 0x80, 0xa1, 0x07, 0x06, 0x05, 0x2b, 0x0c, 0x00, 0x81, 0x5a, 0xbe,
                    0x14, 0x28, 0x12, 0x06, 0x07, 0x2b, 0x0c, 0x00, 0x82, 0x1d, 0x81, 0x48, 0xa0, 0x07, 0xa0, 0x05,
                    0x03, 0x03, 0x00, 0x08, 0x00 } },
        { "msg2", { 0x1, 0x2, 0x3 } },
        { "msg3", { 0x1, 0x2 } },
    };

    // what if key not found?
    std::unordered_map<std::string, binary_message>::const_iterator it = table.find(key);
    if (it != table.end())
        return it->second;
    //else
    //  ???  throw an exception?  Something else?  Or should I be returning a std::unordered_map<std::string, binary_message>::const_iterator?
}

int main()
{
    const binary_message& msg7 = lookup_msg("msg1");

    // do whatever with bytes

    return 0;
}

3 个答案:

答案 0 :(得分:2)

这是Boost.Optional的一个很好的用例:

static boost::optional<const binary_message&> lookup_msg(const std::string& key) {
    ...
    if (it != table.end()) {
        return it->second; // we have a value
    }
    else {
        return boost::none; // we do not have a value
    }
}

这里的想法是返回类型本身知道它是否有值,没有歧义。

请注意,在这里返回迭代器实际上并不是一个选项,因为table是函数的静态本地 - 因此调用者没有任何东西可以与之进行比较。

答案 1 :(得分:1)

这是一个设计选择。您必须确定在正常条件下是否没有错误,是否可以找到无法找到的条目。

例如,如果您的数据结构代表街道上的房屋,但并非街道上的所有空间都包含房屋,那么找不到房屋不是错误,应该返回一个迭代器来与end进行比较(或者指针可以是空的,或者是一面旗帜,或者其他一些......)

另一方面,如果街道上的每个可访问空间都必须包含房屋,那么如果找不到房屋,则抛出异常是合适的选择。

即使您采用第一种方法,如果您愿意,搜索超出街道最大地址的房屋仍然会引发异常。

如果您不确定使用哪种方法,请考虑典型用例。如果你抛出一个异常,你的用户将不需要手动检查每个请求是否找到了一个项目,如果没有找到一个项目就简化了他们的工作就会阻止他们进入他们的轨道(错误,中止等)。

另一方面,如果他们希望不定期找到一个项目,那么每次都让他们捕获异常是烦人的,而且效率低下。

也没有什么可以阻止你提供两个功能,它们不会以不同的方式找到一个项目,但是不要过度思考......:)

答案 2 :(得分:0)

如果可以与容器的成员函数返回的end元素进行比较,则将迭代器返回到end元素非常有用。抛出异常很有用,因为如果返回指向坏内存的迭代器,访问该数据可能也会引发异常。您也可以执行其他类似map类型的操作,并返回一对结果(true / false)和迭代器结果。

迭代

std::unordered_map<std::string, binary_message>::const_iterator it = table.find(key);
if (it != table.end())
    return it->second;
else
    return table.end();

const binary_message& msg7 = lookup_msg("msg1");
if(msg7 == table.end())
 // whatever

异常

std::unordered_map<std::string, binary_message>::const_iterator it = table.find(key);
if (it != table.end())
    return it->second;
else
    throw some_exception("Couldn't find element.");

std::unordered_map<std::string, binary_message>::const_iterator it = table.find(key);
if (it != table.end())
    return std::pair<bool, iterator_type>(true, it->second);
else
    return std::pair<bool, iterator_type>(false, table.end());

const binary_message& msg7 = lookup_msg("msg1");
if(msg7.first)
  // Do stuff
else
  // Error out