为什么 `std::string::find()` 不是 return 失败时的结束迭代器?

Why does `std::string::find()` not return the end iterator on failures?

我发现 std::string::find 的行为与标准 C++ 容器不一致。

例如

std::map<int, int> myMap = {{1, 2}};
auto it = myMap.find(10);  // it == myMap.end()

但是对于一个字符串,

std::string myStr = "hello";
auto it = myStr.find('!');  // it == std::string::npos

为什么失败的 myStr.find('!') return myStr.end() 而不是 std::string::npos

由于std::string与其他容器相比有些特殊,我想知道这背后是否有真正的原因。 (令人惊讶的是,我在任何地方都找不到任何人对此提出质疑)。

首先,众所周知,std::string 界面臃肿且不一致,请参阅 Herb Sutter 关于此主题的 Gotw84。但是,尽管如此,std::string::find return 索引背后还是有原因的:std::string::substr。这个方便的成员函数对索引进行操作,例如

const std::string src = "abcdefghijk";

std::cout << src.substr(2, 5) << "\n";

您可以实现 substr,使其接受字符串中的迭代器,但这样一来我们就不需要等待很长时间,因为大声抱怨 std::string 不可用且违反直觉。因此,鉴于 std::string::substr 接受索引,您如何在上述输入字符串中找到 'd' 第一次出现的索引,以便打印出从该子字符串开始的所有内容?

const auto it = src.find('d'); // imagine this returns an iterator

std::cout << src.substr(std::distance(src.cbegin(), it));

这也可能不是您想要的。因此我们可以让 std::string::find return 一个索引,这里我们是:

const std::string extracted = src.substr(src.find('d'));

如果您想使用迭代器,请使用 <algorithm>。他们允许您将上述内容作为

auto it = std::find(src.cbegin(), src.cend(), 'd');

std::copy(it, src.cend(), std::ostream_iterator<char>(std::cout));

这是因为std::string有两个接口:

  • 通用的基于迭代器的接口在所有容器
  • 上找到
  • std::string 特定的 index 基于接口

std::string::find 是基于 index 的界面的一部分,因此 returns indices.

使用std::find使用基于通用迭代器的接口。

如果您不想使用基于索引的界面(不要这样做),请使用 std::vector<char>