c++ - 通过move高效地将元组插入到容器中

标签 c++ c++11 move-semantics emplace

我是一个move语义初学者。这段代码是:

template <typename... Args>
void foo(const Args & ... args){
    map<tuple<Args...>, int> cache;
    auto result = cache.emplace(move(make_tuple(args ...)),1);
    //...
    }

比以下更有效:

template <typename... Args>
void foo(const Args & ... args){
    map<tuple<Args...>, int> cache;
    tuple<Args...> t(args...);
    auto result = cache.insert(make_pair(t,1));
    //...
    }

特别是如果 args 包含一些大对象?

同样的问题,但使用 std::vector (因此不需要 make_pairmake_tuple)

最佳答案

由于这是为了内存,所以这两种选择都不是一个好主意。

对于唯一 key 容器,emplaceinsert (除非 insert 传递 value_type - 即 pair<const Key, Value> )可以无条件分配内存并首先构造键值对,然后如果键已经存在则销毁该对并释放内存;如果您的 key 已经存在,这显然是昂贵的。 (他们需要这样做,因为在一般情况下,您必须先构造 key ,然后才能检查它是否存在,并且必须直接在其最终位置构造 key 。)

但是,您还希望避免不必要地复制 key ,因此插入 value_type不好-Key其中是 const 限定的,因此无法从中 move 。

最后,您还希望避免额外的查找。不像内存分配那么昂贵,但仍然很好地保存它。

因此,我们需要先查找key,只调用emplace如果 key 不在 map 上。在 C++11 中,只允许同构查找,因此您必须复制一份 args... .

map<tuple<Args...>, int> cache;
auto key = std::make_tuple(args...);
auto it = cache.lower_bound(key); // *it is the first element whose key is
                                  // not less than 'key'
if(it != cache.end() && it->first == key) {
    // key already in the map, do what you have to do
}
else {
    // add new entry, using 'it' as hint and moving 'key' into container.
    cache.emplace_hint(it, std::move(key), /* value */);
}

在 C++14 中,您可以进行异构查找,这意味着您可以保存拷贝以供实际需要时使用:

map<tuple<Args...>, int, less<>> cache; // "diamond functor" enables hetergeneous lookup
auto key = std::tie(args...); // this is a tuple<const Args&...> - a tuple of references!
auto it = cache.lower_bound(key); // *it is the first element whose key is
                                  // not less than 'key'
if(it != cache.end() && it->first == key) {
    // key already in the map, do what you have to do
}
else {
    // add new entry, copying args...
    cache.emplace_hint(it, key, /* value */);
}

关于c++ - 通过move高效地将元组插入到容器中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36906183/

相关文章:

c++11 - shared_ptr<T> 到 const shared_ptr<const T>&

c++ - 当您将文字常量分配给右值引用时会发生什么?

c++ - MFC为OPOS添加Typelib或ActiveX

c++ - 何时使用 =default 使析构函数默认?

c++ - 从 MPC(Makefile、项目和工作区创建器)添加 MAKEFLAGS

c++ - 为什么wxWidgets在调用new之后从不调用delete?

c++ - 类型已知时如何调用 std::forward

c++ - 通过 return 构造元组时的 move 规则

c++ - 指向数据成员的数据成员的指针

c++ - C++ 中对 WinMain@16 的 undefined reference