Как работает boost :: unordered_map.emplace (Args && ... args)? - PullRequest
11 голосов
/ 29 января 2011

Согласно документации it:

Вставляет объект, построенный с аргументами args, в контейнер, если и только если в контейнере нет элемента сэквивалентный ключ.

Но единственные объекты, которые могут быть вставлены в unordered_map, имеют тип std::pair<Key const, Mapped> (потому что и ключ, и значение необходимы для вставляемого объекта), который известенвозьмите конструктор с двумя аргументами.Так почему же он использует форму функции variadic?Конечно, есть кое-что, чего я совершенно не понимаю в этом.

Ответы [ 2 ]

8 голосов
/ 29 января 2011

См. эту SO статью о emplace_back против push_back.По сути, он позволяет построить объект из аргументов, переданных в него, без необходимости создания объекта, который будет передан первым.Это экономит накладные расходы, удаляя конструкцию копирования, которая обычно происходит в результате создания объектов для вставки.

Таким образом, вы можете обойтись без этого:

unordered_map<int,int> foo;
foo.emplace(4, 5);

вместо

foo.insert(std::make_pair(4, 5));

Еще лучше, (и если я не ошибаюсь) вы можете пройти по этому маршруту:

struct Bar{
    int x,y;
    Bar(int _x, int _y) : x(_x), y(_y){}
};

unordered_map<int,Bar> baz;
baz.emplace(4, 5, 6);

И взято из вики на C ++ 0x :

Из-за природы формулировки ссылок на rvalue и некоторых изменений в формулировке ссылок на lvalue (регулярные ссылки) ссылки на rvalue позволяют разработчикам обеспечить идеальную пересылку функций.В сочетании с шаблонами с переменными параметрами эта возможность позволяет использовать шаблоны функций, которые могут идеально передавать аргументы другой функции, которая принимает эти конкретные аргументы.Это наиболее полезно для пересылки параметров конструктора, для создания фабричных функций, которые будут автоматически вызывать правильный конструктор для этих конкретных аргументов.

, который работает следующим образом:

template<typename TypeToConstruct> struct SharedPtrAllocator {

    template<typename ...Args> std::shared_ptr<TypeToConstruct> construct_with_shared_ptr(Args&&... params) {
        return std::shared_ptr<TypeToConstruct>(new TypeToConstruct(std::forward<Args>(params)...));
    }
}

Опять же, бесстыдно украденный из упомянутой выше статьи Wiki.

5 голосов
/ 15 сентября 2013

Теперь, когда стандартная библиотека C ++ интегрировала эту часть Boost:

С http://en.cppreference.com

#include <iostream>
#include <utility>
#include <tuple>

#include <unordered_map>

int main(){
    std::unordered_map<std::string, std::string> m;

    // uses pair's piecewise constructor
    m.emplace(std::piecewise_construct,
        std::forward_as_tuple("c"),
        std::forward_as_tuple(10, 'c'));

    for (const auto &p : m) {
        std::cout << p.first << " => " << p.second << '\n';
    }
}

std::piecewise_constructявляется константой, которая не оставляет двусмысленности относительно того, как будут использоваться аргументы

  • Первый кортеж будет использоваться для создания ключа
  • Второй - для создания значения
...