Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does boost::unordered_map.emplace(Args&&... args) work?

According to the documentation it:

Inserts an object, constructed with the arguments args, in the container if and only if there is no element in the container with an equivalent key.

But the only objects which can be inserted into an unordered_map have type std::pair<Key const, Mapped>(because both a key and a value are needed for an object to be inserted), which is known to take a constructor with exactly two arguments. So why does it use the variadic function form? Surely there is something I am totally not understanding about this.

like image 712
Mankarse Avatar asked Jan 29 '11 14:01

Mankarse


1 Answers

See this SO article on emplace_back vs. push_back. Essentially, it allows an object to be constructed from the arguments passed into it without needing to create the object to be passed in first. It saves on overhead by removing a copy construction which normally happens as the result of creating objects to be inserted.

So you can get away with this:

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

instead of

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

Even better, (and if I'm not mistaken), you can go through this route:

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

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

And taken from the Wiki on C++0x:

Due to the nature of the wording of rvalue references, and to some modification to the wording for lvalue references (regular references), rvalue references allow developers to provide perfect function forwarding. When combined with variadic templates, this ability allows for function templates that can perfectly forward arguments to another function that takes those particular arguments. This is most useful for forwarding constructor parameters, to create factory functions that will automatically call the correct constructor for those particular arguments.

Which works in the following manner:

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)...));
    }
}

Again, shamelessly stolen from the Wiki article mentioned above.

like image 164
wheaties Avatar answered Oct 04 '22 09:10

wheaties