C++ unordered_map<字符串,...> 查找而不构造字符串
C++ unordered_map<string, ...> lookup without constructing string
我有C++代码来调查一个大字符串并匹配许多子字符串。 我尽可能避免构造 std::strings,通过像这样编码子字符串:
char* buffer, size_t bufferSize
但是,在某些时候,我想在其中一个中查找一个子字符串:
std::unordered_map<std::string, Info> stringToInfo = {...
所以,要做到这一点,我去:
stringToInfo.find(std::string(buffer, bufferSize))
这将构造一个 std::string 的唯一目的是查找。
我觉得我可以在这里做一个优化,通过...将unordered_map的键类型更改为某种临时字符串冒名顶替者,像这样的类......
class SubString
{
char* buffer;
size_t bufferSize;
// ...
};
。这与 std::string 执行相同的逻辑来哈希和比较,但在它被销毁时不会释放其缓冲区。
所以,我的问题是:有没有办法让标准类来做到这一点,还是我自己编写这个类?
你想要做的称为异构查找。 自 C++14 以来,std::map::find
和std::set::find
都支持它(请注意函数的版本 (3) 和 (4),它们在查找值类型上模板化)。 对于无序容器来说,这更复杂,因为它们需要被告知或找到所有键类型的哈希函数,这些函数将为相同的文本生成相同的哈希值。 正在考虑一项关于未来标准的提案:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0919r0.html
同时,您可以使用另一个已经支持异构查找的库,例如boost::unordered_map::find
.
如果你想坚持std::unordered_map
,你可以通过在unordered_map
旁边存储一个可以重新分配值的std::string
成员来避免创建太多的字符串临时,然后将该string
传递给find
。 可以将其封装在自定义容器类中。
另一种方法是编写一个自定义类以用作无序容器键:
struct CharPtrOrString
{
const char* p_;
std::string s_;
explicit CharPtrOrString(const char* p) : p_{p} { }
CharPtrOrString(std::string s) : p_{nullptr}, s_{std::move(s)} { }
bool operator==(const CharPtrOrString& x) const
{
return p_ ? x.p_ ? std::strcmp(p_, x.p_) == 0
: p_ == x.s_
: x.p_ ? s_ == x.p_
: s_ == x.s_;
}
struct Hash
{
size_t operator()(const CharPtrOrString& x) const
{
std::string_view sv{x.p_ ? x.p_ : x.s_.c_str()};
return std::hash<std::string_view>()(sv);
}
};
};
然后,您可以从std::string
构造CharPtrOrString
以用于无序容器密钥,但每次调用find
时,都可以从您的const char*
廉价地构建一个。 请注意,上面的operator==
必须弄清楚你做了什么(使用的约定是,如果指针nullptr
,那么std::string
成员正在使用中),以便比较正在使用的成员。 哈希函数必须确保具有特定文本值的std::string
将产生与const char*
相同的哈希(默认情况下,GCC 7.3 和/或 Clang 6不会 - 我同时使用两者并记住一个有问题,但不是哪个)。
在 C++20 中,您现在可以执行以下操作:
// struct is from "https://www.cppstories.com/2021/heterogeneous-access-cpp20/"
struct string_hash {
using is_transparent = void;
[[nodiscard]] size_t operator()(const char *txt) const {
return std::hash<std::string_view>{}(txt);
}
[[nodiscard]] size_t operator()(std::string_view txt) const {
return std::hash<std::string_view>{}(txt);
}
[[nodiscard]] size_t operator()(const std::string &txt) const {
return std::hash<std::string>{}(txt);
}
};
// Declaration of map
std::unordered_map<std::string, Info, string_hash, std::equal_to<>> map;
std::string_view key = "foo";
if (map.find(key))
{
// do something here
}
请注意,使用[]
时您仍然需要std::string
。可能有办法解决这个问题,但我不太确定
- 使用正则表达式regex_search在字符串中查找字符串
- 按类型与字符串查找对象
- 使用C RTTI(内置)通过字符串查找功能指针
- 关于获取行和字符串查找函数的问题
- 字符串查找方法找不到第一字母
- C++ 字符串.查找()
- 遇到字符串::查找的问题
- 将一个数组作为子字符串查找到另一个数组中
- 字符串查找第一个非的 C++ 问题
- 如何将通配符与字符串::查找一起使用
- 字符串::查找问题 (C++)
- 性能标准::strstr vs. 标准::字符串::查找
- C++字符串::查找崩溃应用程序
- 使用字符串查找单词的正确方法是什么
- 如何在<string>没有 std::string 中介的情况下制作一个支持通过 C 字符串查找的集合?
- 使用C++根据行中的第一个字符串查找行(仅一个)
- Borland字符串::查找bug
- std::map如何通过字符串查找元素
- 字符串查找函数返回奇数
- 如何使用子字符串查找数字行的正确部分