std :: map insert & amp; & amp; перегрузка вызывает копирование

Глядя на этот интересный разговор:

CppCon 2017: Мэтт Кулукундис «Создание быстрой, эффективной и удобной для кэширования хэш-таблицы, шаг за шагом»

Около минуты 38:32 он упоминает, что

void Benchmark_Slow(int iters) {
std::unordered_map<string, int> m;
std::pair<const string, int> p = {};
while (iters--) m.insert(p)
}

примерно в 2 раза медленнее, чем следующий вариант

void Benchmark_Fast(int iters) {
std::unordered_map<string, int> m;
const std::pair<const string, int> p = {};
while (iters--) m.insert(p)
}

Я все еще думаю о том, почему && перегрузка (1) будет выбрана.

  • std::pair<iterator,bool> insert( value_type&& value ); (1)

  • std::pair<iterator,bool> insert( const value_type& value ); (3)

где value_typeявляется std::pair<const Key, T>,

Ведь мы не двигаем ценности, поэтому в моем понимании выражение p должно быть lvalue, а не x / prvalue, верно? Может ли кто-нибудь просветить меня?

1

Решение

Вы не принимаете проблемные перегрузки:

std::pair<iterator,bool> insert(const value_type& value); // (1)

template< class P >
std::pair<iterator,bool> insert(P&& value); // (2)

P выводится как value_type&,

2

Другие решения

  1. Перегрузка шаблона называется (перегрузка (2) на cppreference)
  2. Перегрузка шаблона эквивалентна emplace
  3. emplace не медленнее, что insert и скорее в общем случае, но …

Но, emplace допускает одно злоупотребление, и это когда вы неоднократно пытаетесь вставить один и тот же ключ. И тест делает именно это (обратите внимание, что while). Я бы сказал, что это просто эталон, показывающий поведение, когда вы намеренно стреляете себе в ногу. В реальном мире я не думаю, что можно было бы сделать это через emplace или же insert,

В C ++ 17 это было исправлено одним способом, который требует изменения вашего кода:

  1. try_emplace функция https://isocpp.org/files/papers/n4279.html
1

По вопросам рекламы [email protected]