What are the differences between them, and when should you use each?
I have tried a few tests on an old laptop and there seems to be no significant performance difference for storing basic types like ints and longs. I think one of the main difference is boost container emplace methods dont support std::piecewise_construct and tuples, which causes additional overhead.
Edit: the stuff I'm working on already has a lot of boost features, so I'm not worried about compatibility issues with boost libraries.
CodePudding user response:
The Boost ones have some features that do not exist in the standard library. Off the top of my head:
Boost Hash, which is more flexible and easier to customize than specializing
std::hash<>
(though specializingboost::hash<>
is also supported; the easier route is to implement ainline friend size_t hash_value(T const&)
which will "magically" be picked up by the defaulthash<>
implementationBoost tends to support heterogeneous lookup better (look for extended find/insert signatures)
The ordered versions may have extra constructors to efficiently construct over known ordered sequences
In general Boost containers (including others from the Boost Container library) have more guarantees/options:
- (better) support for stateful allocators (including scoped_allocator_adaptor, so with full
uses_allocator
/allocator_arg_t
support) - constructors don't allocate
- some support for incomplete types in the the template arguments
- (better) support for stateful allocators (including scoped_allocator_adaptor, so with full
As far as I know piecewise construction is perfectly fine in Boost. E.g. Change notes lists for 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
Summary
I don't expect significant differences in performance.
Quality of implementation differences will exist. Boost's will probably be a bit slower to compile and support older compiler versions.
BONUS
In reply to the comments, here's a sample outlining some of the features mentioned above and in particular the use of piecewise emplacement:
#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);
}
Prints
m: {([43, "forty-three"], "not the answer"), ([42, "forty-two"], "the answer")}