简体   繁体   English

STL 容器 find_or_create()

[英]STL container find_or_create()

Is there some sort of STL facility for doing a find_or_create() on STL containers?是否有某种 STL 工具可以在 STL 容器上执行find_or_create()

Eg in the case of unordered_map, I frequently find myself needing to retrieve some value and create it if no value exists.例如,在 unordered_map 的情况下,我经常发现自己需要检索一些值并在不存在值时创建它。 There are plenty of functions for conditionally inserting into a map, but all of them result in creating a new value right away, even if one is already present in the map:有很多函数可以有条件地插入 map,但所有这些函数都会立即创建一个新值,即使 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;
}

Output: Output:

Created via insert
Created via emplace
Created via piecewise construct
Created via try_emplace
Created via operator[]

In the event that object A is costly to create (takes a long time to construct, acquires system resources, etc.) these unnecessary creations can be undesirable.如果 object A的创建成本很高(需要很长时间来构建、获取系统资源等),这些不必要的创建可能是不可取的。 This often leads me to create a template like so:这经常导致我创建一个这样的模板:

#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;
}

Output: Output:

Created via find_or_create

Is there a better (ie simpler) way to achieve this via STL, or is a template like this one the way to go?有没有更好(即更简单)的方法来通过 STL 实现这一点,或者像这样的模板是 go 的方法吗?

try_emplace is what you want. try_emplace是你想要的。 Your problem is that you are deliberately constructing an A , instead of passing the arguments to the constructor, which it may or may not use to construct the A .您的问题是您故意构造A ,而不是将arguments传递给构造函数,它可能会或可能不会用于构造A

What you want is this:你想要的是这样的:

auto &val4 = *m.try_emplace(0, "try_emplace").first;

Your find-or-create function would be useful if you can't create the object via constructor call (ie: instances get created via factory functions or whatever).如果您无法通过构造函数调用创建 object(即:通过工厂函数或其他方式创建实例),您的查找或创建 function 将很有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM