STL 容器 find_or_create()
STL container find_or_create()
是否有某种 STL 工具可以在 STL 容器上执行 find_or_create()
?
例如在 unordered_map 的情况下,我经常发现自己需要检索一些值并在不存在值时创建它。有很多函数可以有条件地插入到地图中,但所有这些函数都会立即创建一个新值,即使地图中已经存在一个值也是如此:
#include <iostream>
#include <unordered_map>
struct A {
A() = default;
A(std::string_view method) {
std::cout << "Created via " << method << std::endl;
}
};
int main() {
std::unordered_map<int, A> m{
{0, A{}}
};
// Get a reference to m[0]; create it if it doesn't exist
// Key 0 is already in the map, so these calls *should* do little work
auto &val1 = *m.insert(std::make_pair(0, A{"insert"})).first;
auto &val2 = *m.emplace(0, A{"emplace"}).first;
auto &val3 = *m.emplace(std::piecewise_construct,
std::make_tuple(0),
std::make_tuple("piecewise construct")).first;
auto &val4 = *m.try_emplace(0, A{"try_emplace"}).first;
auto &val5 = (m[0] = A{"operator[]"});
return 0;
}
输出:
Created via insert
Created via emplace
Created via piecewise construct
Created via try_emplace
Created via operator[]
如果对象 A
的创建成本很高(需要很长时间构建、获取系统资源等),这些不必要的创建可能是不受欢迎的。这通常会导致我创建这样的模板:
#include <iostream>
#include <unordered_map>
struct A {
A() = default;
A(std::string_view method) {
std::cout << "Created via " << method << std::endl;
}
};
template<class Map, class OnCreate>
typename Map::mapped_type &find_or_create(Map &map, const typename Map::key_type &key, const OnCreate &on_create) {
auto it = map.find(key);
if (it == map.end())
it = map.emplace(key, on_create(key)).first;
return it->second;
}
int main() {
std::unordered_map<int, A> m;
// Get a reference to m[0]; create it if it doesn't exist
auto &val1 = find_or_create(m, 0, [](const int &) { return A{"find_or_create"}; });
auto &val2 = find_or_create(m, 0, [](const int &) { return A{"never created"}; });
return 0;
}
输出:
Created via find_or_create
是否有更好(即更简单)的方法通过 STL 实现此目的,或者像这样的模板是否可行?
try_emplace
就是你想要的。你的问题是你故意构造一个A
,而不是将参数传递给构造函数,它可能会也可能不会用于构造 A
.
你要的是这个:
auto &val4 = *m.try_emplace(0, "try_emplace").first;
如果您不能通过构造函数调用创建对象(即:通过工厂函数或其他方式创建实例),您的查找或创建函数将很有用。
是否有某种 STL 工具可以在 STL 容器上执行 find_or_create()
?
例如在 unordered_map 的情况下,我经常发现自己需要检索一些值并在不存在值时创建它。有很多函数可以有条件地插入到地图中,但所有这些函数都会立即创建一个新值,即使地图中已经存在一个值也是如此:
#include <iostream>
#include <unordered_map>
struct A {
A() = default;
A(std::string_view method) {
std::cout << "Created via " << method << std::endl;
}
};
int main() {
std::unordered_map<int, A> m{
{0, A{}}
};
// Get a reference to m[0]; create it if it doesn't exist
// Key 0 is already in the map, so these calls *should* do little work
auto &val1 = *m.insert(std::make_pair(0, A{"insert"})).first;
auto &val2 = *m.emplace(0, A{"emplace"}).first;
auto &val3 = *m.emplace(std::piecewise_construct,
std::make_tuple(0),
std::make_tuple("piecewise construct")).first;
auto &val4 = *m.try_emplace(0, A{"try_emplace"}).first;
auto &val5 = (m[0] = A{"operator[]"});
return 0;
}
输出:
Created via insert
Created via emplace
Created via piecewise construct
Created via try_emplace
Created via operator[]
如果对象 A
的创建成本很高(需要很长时间构建、获取系统资源等),这些不必要的创建可能是不受欢迎的。这通常会导致我创建这样的模板:
#include <iostream>
#include <unordered_map>
struct A {
A() = default;
A(std::string_view method) {
std::cout << "Created via " << method << std::endl;
}
};
template<class Map, class OnCreate>
typename Map::mapped_type &find_or_create(Map &map, const typename Map::key_type &key, const OnCreate &on_create) {
auto it = map.find(key);
if (it == map.end())
it = map.emplace(key, on_create(key)).first;
return it->second;
}
int main() {
std::unordered_map<int, A> m;
// Get a reference to m[0]; create it if it doesn't exist
auto &val1 = find_or_create(m, 0, [](const int &) { return A{"find_or_create"}; });
auto &val2 = find_or_create(m, 0, [](const int &) { return A{"never created"}; });
return 0;
}
输出:
Created via find_or_create
是否有更好(即更简单)的方法通过 STL 实现此目的,或者像这样的模板是否可行?
try_emplace
就是你想要的。你的问题是你故意构造一个A
,而不是将参数传递给构造函数,它可能会也可能不会用于构造 A
.
你要的是这个:
auto &val4 = *m.try_emplace(0, "try_emplace").first;
如果您不能通过构造函数调用创建对象(即:通过工厂函数或其他方式创建实例),您的查找或创建函数将很有用。