C++ STD 无序 Set/Map 与 Boost 无序 Set/Map
C++ STD Unordered Set/Map vs Boost Unordered Set/Map
它们之间有什么区别,应该在什么时候使用它们?
我在一台旧笔记本电脑上进行了一些测试,在存储基本类型(如 int 和 long)方面似乎没有明显的性能差异。我认为主要区别之一是提升容器 emplace 方法不支持 std::piecewise_construct 和元组,这会导致额外的开销。
编辑:我正在处理的东西已经有很多增强功能,所以我不担心与增强库的兼容性问题。
Boost 有一些标准库中不存在的特性。在我的脑海中:
Boost Hash,它比特化 std::hash<>
更灵活且更容易定制(尽管也支持特化 boost::hash<>
;更简单的方法是实现 inline friend size_t hash_value(T const&)
默认 hash<>
实现
将“神奇地”拾取
Boost 倾向于更好地支持异构查找(寻找扩展的 find/insert 签名)
有序版本可能有额外的构造函数来有效地构建已知的有序序列
一般来说,Boost 容器(包括来自 Boost Container 库的其他容器)有更多 guarantees/options:
- (更好)支持状态分配器(包括 scoped_allocator_adaptor,因此具有完整的
uses_allocator
/allocator_arg_t
支持)
- 构造函数不分配
- 模板参数中对不完整类型的一些支持
据我所知,分段构造在 Boost 中非常好。例如。更改 1.48.0 的注释列表:
* `emplace` used to emulate the variadic pair constructors that
appeared in early C++0x drafts. Since they were removed it no
longer does so. It does emulate the new `piecewise_construct`
pair constructors - only you need to use
`boost::piecewise_construct`. To use the old emulation of
the variadic constructors define
总结
我预计性能不会有显着差异。
将存在实施质量差异。 Boost 的编译和支持旧编译器版本可能会慢一些。
奖金
作为对评论的回复,这里有一个示例,概述了上面提到的一些功能,特别是分段放置的使用:
#include <boost/unordered_map.hpp>
#include <iomanip>
#include <fmt/ranges.h>
#include <fmt/ostream.h>
struct MyKey {
MyKey(int i, std::string s) : _i(i), _s(std::move(s)) {}
bool operator==(MyKey const&) const = default;
private:
int _i;
std::string _s;
friend size_t hash_value(MyKey const& mk) {
using boost::hash_value;
size_t seed = hash_value(mk._i);
boost::hash_combine(seed, hash_value(mk._s));
return seed;
}
friend auto& operator<<(auto& os, MyKey const& mk) {
return os << "[" << mk._i << ", " << std::quoted(mk._s) << "]";
}
};
int main() {
boost::unordered_map<MyKey, std::string> m;
m.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(42, "forty-two"),
boost::make_tuple("the answer"));
m.emplace(std::piecewise_construct,
std::/*make_*/tuple(43, "forty-three"),
std::/*make_*/tuple("not the answer"));
fmt::print("m: {}\n", m);
}
版画
m: {([43, "forty-three"], "not the answer"), ([42, "forty-two"], "the answer")}
它们之间有什么区别,应该在什么时候使用它们?
我在一台旧笔记本电脑上进行了一些测试,在存储基本类型(如 int 和 long)方面似乎没有明显的性能差异。我认为主要区别之一是提升容器 emplace 方法不支持 std::piecewise_construct 和元组,这会导致额外的开销。
编辑:我正在处理的东西已经有很多增强功能,所以我不担心与增强库的兼容性问题。
Boost 有一些标准库中不存在的特性。在我的脑海中:
Boost Hash,它比特化
将“神奇地”拾取std::hash<>
更灵活且更容易定制(尽管也支持特化boost::hash<>
;更简单的方法是实现inline friend size_t hash_value(T const&)
默认hash<>
实现Boost 倾向于更好地支持异构查找(寻找扩展的 find/insert 签名)
有序版本可能有额外的构造函数来有效地构建已知的有序序列
一般来说,Boost 容器(包括来自 Boost Container 库的其他容器)有更多 guarantees/options:
- (更好)支持状态分配器(包括 scoped_allocator_adaptor,因此具有完整的
uses_allocator
/allocator_arg_t
支持) - 构造函数不分配
- 模板参数中对不完整类型的一些支持
- (更好)支持状态分配器(包括 scoped_allocator_adaptor,因此具有完整的
据我所知,分段构造在 Boost 中非常好。例如。更改 1.48.0 的注释列表:
* `emplace` used to emulate the variadic pair constructors that appeared in early C++0x drafts. Since they were removed it no longer does so. It does emulate the new `piecewise_construct` pair constructors - only you need to use `boost::piecewise_construct`. To use the old emulation of the variadic constructors define
总结
我预计性能不会有显着差异。
将存在实施质量差异。 Boost 的编译和支持旧编译器版本可能会慢一些。
奖金
作为对评论的回复,这里有一个示例,概述了上面提到的一些功能,特别是分段放置的使用:
#include <boost/unordered_map.hpp>
#include <iomanip>
#include <fmt/ranges.h>
#include <fmt/ostream.h>
struct MyKey {
MyKey(int i, std::string s) : _i(i), _s(std::move(s)) {}
bool operator==(MyKey const&) const = default;
private:
int _i;
std::string _s;
friend size_t hash_value(MyKey const& mk) {
using boost::hash_value;
size_t seed = hash_value(mk._i);
boost::hash_combine(seed, hash_value(mk._s));
return seed;
}
friend auto& operator<<(auto& os, MyKey const& mk) {
return os << "[" << mk._i << ", " << std::quoted(mk._s) << "]";
}
};
int main() {
boost::unordered_map<MyKey, std::string> m;
m.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(42, "forty-two"),
boost::make_tuple("the answer"));
m.emplace(std::piecewise_construct,
std::/*make_*/tuple(43, "forty-three"),
std::/*make_*/tuple("not the answer"));
fmt::print("m: {}\n", m);
}
版画
m: {([43, "forty-three"], "not the answer"), ([42, "forty-two"], "the answer")}