当返回迭代器时,最好返回迭代程序类型还是实际对象



在下面的代码中,会在哈希表中查找一个值,如果在映射中找不到键,我很困惑该怎么办。

返回迭代器以便调用方可以检查它更好吗?

提出一个例外更好吗?

还是做点别的?

这是代码:

#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;
}

这是Boost的一个很好的用例。可选:

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是函数的静态本地,所以调用方没有任何东西可以将其与之进行比较。

这是一个设计选择。你必须决定在没有错误的正常条件下,找不到条目是否可以接受。

例如,如果您的数据结构表示街道上的房屋,但并非街道上的所有空间都包含房屋,则找不到房屋不是错误,应该返回一个迭代器来与end(或可以为null的指针、标志或诸如此类的东西)进行比较

另一方面,如果街道上的每个无障碍空间都必须包含一栋房子,那么如果找不到房子,那么破例是一个合适的选择。

即使你选择第一种方法,如果你愿意的话,在街道的最大地址之外寻找房子仍然可以破例。

如果您不确定使用哪种方法,请考虑典型的用例。如果您抛出异常,您的用户将不需要手动检查每个请求是否找到了一个项目,如果找不到项目是导致他们无法跟踪的原因(错误、中止等),则简化了他们的工作。

另一方面,如果他们希望不定期找到一个项目,那么让他们每次都捕捉异常是令人讨厌的,也是低效的。

也没有什么可以阻止你提供两个功能,这两个功能可以处理找不到不同的物品,但不要想太多。:)

如果可以与容器的成员函数返回的结束元素进行比较,则将迭代器返回到结束元素非常有用。抛出异常很有用,因为如果返回指向坏内存的迭代器,访问该数据也可能抛出异常。您还可以像其他类似映射的类型那样返回一对结果(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

最新更新