emplace, emplace_back, etc.

Same as the previously learned containers such as map and set, the C++11 standard also adds emplace() and emplace_hint() member methods to the unordered_map container. This section will introduce their usage in detail.

We know that adding a new key-value pair to an existing unordered_map container can be done by calling the insert() method, but there is actually a better way, that is, using the emplace() or emplace_hint() method, which completes “into the container Adding new key-value pairs” is more efficient than the insert() method.

As for why emplace() and emplace_hint() are more efficient than insert(), you can read the article “Why emplace() and emplace_hint() are more efficient than insert()”. Although the object of this article is the map container, But as far as these three methods are concerned, the unordered_map container is the same as the map container.

emplace() method in unordered_map

The usage of the emplace() method is very simple, and its syntax is as follows:

template <class... Args>
    pair<iterator, bool> emplace ( Args & amp; & amp;... args );

Among them, the parameter args indicates that the value of the two elements required to create a new key-value pair can be directly passed to this method, and the first element will be used as the key of the key-value pair, and the other Value as a key-value pair. In other words, this method does not require us to manually create key-value pairs, it will do this work internally.

emplace(key,value)

Another thing to note is that the return value of this method is a pair type value, which contains an iterator and a bool type value:

  • When emplace() successfully adds a new key-value pair, the returned iterator points to the newly added key-value pair, and the bool value is True;
  • When emplace() fails to add a new key-value pair, it means that the container already contains a key-value pair with the same key. At this time, the returned iterator points to the key-value pair with the same key in the container, bool value to False.
#include<iostream>
#include<string>
#include <unordered_map>

int main() {
//Create unorder_map container
std::unordered_map<std::string, std::string> u_map;
u_map.emplace("blog", "https://blog.csdn.net/qq_44918090?spm=1010.2135.3001.5343");
for (auto iter = u_map.begin(); iter != u_map.end(); + + iter) {
std::cout << (*iter).first << " " << (*iter).second << std::endl;
}
std::cout << std::endl;
std::pair<std::unordered_map<std::string, std::string>::iterator, bool> ret = u_map.emplace("Baidu","www.baidu.com");
std::cout << ret. second << std::endl;
std::cout << ret.first->first << " " << (*(ret.first)).second;

return 0;
}

output result:

Blog https://blog.csdn.net/qq_44918090?spm=1010.2135.3001.5343

1
Baidu www.baidu.com Please press any key to continue. . .

【C++11】Methods to improve program performance – emplace_back and unordered containers, written in C++11, will generate temporary objects compared to insert or push_back

C++11 has made great improvements in performance, minimizing memory movement and copying. In addition to the aforementioned rvalue references, there are the following two:

  • The empalce series functions avoid memory copying and moving by directly constructing objects;
  • The unordered container is not sorted when inserting elements, which improves the insertion efficiency, but if the keyword is customized, a hash function and a comparison function need to be provided

emplace series functions

Before C++11, the commonly used method for inserting data into vector was push_back. Starting from C++11, empalce and emplace_back methods are provided. These methods can be regarded as substitutes for push_back. They are not only easy to use, but also The performance improvement is also obvious. The usage of emplace_back is as follows:

void Func2() {
struct A {
int a_;
double b_;
A(int a, double b)
:a_(a),
b_(b){
std::cout << "emplace_back" << std::endl;
}
};
std::vector<A> vec;
vec. emplace_back(1, 2.0);
A a(2, 3.0);
vec.push_back(a);
for (auto iter = vec.begin(); iter != vec.end(); + + iter) {
std::cout << (*iter).a_ << " " << (*iter).b_ << std::endl;
}
}

As can be seen from the above code, the emplace_back method is easy to use and can directly construct a temporary object through the constructor. Therefore, when actually coding, we also need to provide the object’s construction method. If not provided, it will be compiled If you report an error, you can comment out the constructor verification.

emplace_back
emplace_back
1 2
twenty three
Please press any key to continue. . .

Compared with push_back, emplace_back has obvious performance advantages. emplace_back improves the insertion performance of containers by reducing memory movement and copying, and can be transformed based on the above code.

void Func3() {
struct A
{
int x;
double y;
std::string z;
//construct
A(int a, double b, std::string c)
:x(a)
, y(b)
, z(c) {
std::cout << "is constructed" << std::endl;
}
//
A(const A & otherA)
:x(otherA.x)
, y(otherA.y)
, z(std::move(otherA.z)) {
std::cout << "is moved" << std::endl;
}
};

std::vector<A> v;
std::cout << "------emplace_back:---------" << std::endl;
v. emplace_back(1, 2, "helloword");

std::cout << "------push_back:---------" << std::endl;
v.push_back(A(3, 4, "china"));
}

operation result:

------emplace_back:---------
is constructed
------push_back:---------
is constructed
is moved
is moved

It can be seen from the results that during the insertion process of the vector, the push_back method is constructed once and moved twice; using emplace_back is only constructed once, and no memory movement is performed.

It can be seen from the above that in actual applications, the emplace series of functions should be used instead of the traditional push_back and other related functions, but it should also be noted that if the class or structure does not provide a constructor, then the emplace series cannot be used function to replace.

Unordered containers

C ++ 11 has added unordered containers, such as: unordered_map/unordered_multimap and unordered_set/unordered_multiset containers. When actually inserting, these containers are not sorted, so they are more efficient than ordered map and set promote.

The underlying implementation of map and set is a red-black tree, and the corresponding underlying implementation of an unordered container is a Hash Table, which will be more efficient due to the fast operation through hashing internally. When using an unordered container, if it is a basic type of data, there is no need to provide a hash function and a comparison function. The method of use is the same as that of ordinary map and set. If the data type is custom, you need to provide a hash function when using it. Greek function and comparison function, the specific code is as follows:

The same point

Emplace is a new member introduced by the new C++11 standard, along with emplace_front and emplace_back. Corresponding to the original operations insert, push_front, and push_back of the container respectively.

Its functions are: insert an element at a specified position, insert an element at the head of the container, and insert an element at the end of the container.

The difference

** When calling push or insert, pass out the object of the element type, and these objects are copied into the container, or create a local temporary object and push it into the container. **The process of using insert() to insert a key-value pair into a map container is to first create the key-value pair, and then copy or move the key-value pair to the specified location in the map container.

When emplace is called, parameters are passed to the constructor of the element type, and emplace members use these parameters to directly construct elements in the memory space managed by the container without copying. The process of using emplace() or emplace_hint() to insert a key-value pair is to directly construct the key-value pair at the specified position in the map container.

#include <iostream>
#include <map> //map
#include <string> //string
using namespace std;

class testDemo
{
public:
    testDemo(int num) :num(num) {
        std::cout << "call constructor" << endl;
    }
    testDemo(const testDemo & amp; other) :num(other.num) {
        std::cout << "Call the copy constructor" << endl;
    }
    testDemo(testDemo & amp; & amp; other) :num(other.num) {
        std::cout << "call move constructor" << endl;
    }
private:
    int num;
};

int main()
{
    //Create an empty map container
    std::map<std::string, testDemo>mymap;

    cout << "insert():" << endl;
    mymap.insert({ "http://c.biancheng.net/stl/", testDemo(1) });
   
    cout << "emplace():" << endl;
    mymap.emplace( "http://c.biancheng.net/stl/:", 1);

    cout << "emplace_hint():" << endl;
    mymap.emplace_hint(mymap.begin(), "http://c.biancheng.net/stl/", 1);
    return 0;
}

The output of the program is:

insert():
call the constructor
call the move constructor
call the move constructor
emplace():
call the constructor
emplace_hint():
call the constructor

Efficiency

In most cases, the emplace function can directly create new elements in the collection without copying or moving existing elements into the collection. Using the emplace function can reduce the overhead of copying or moving constructors, and can provide Insert, push and other functions have higher performance.

But for std::map and std::unordered_map, insert may be faster than emplace in some cases.

Example:

Calling the std::map::insert function needs to pass in a std::pair object. When actually inserting, this pair will be used to copy construct or move construct the actual storage object in the map, which will generate a copy operation.

When the std::map::emplace function is called, a std::pair will be constructed directly at the actual storage location using the incoming parameters, which usually saves one copy operation

However, if the key already exists, insert only needs to complete the key comparison and return directly, while emplace will have to construct a new object in place to start the comparison, and using emplace will require additional construction overhead.

Summary

In most cases, the efficiency of insert is not as good as that of emplace, but if the key already exists, the efficiency of insert is worse than that of emplace.