push_back() vs emplace_back() in C++ Vectors

When adding new elements to C++ Vectors, the push_back() is very commonly used. Unknown to many, there is actually another way of adding new elements to vectors, called the emplace_back() function. In this “vs” tutorial we will analyze the difference between the push_back() and emplace_back() functions in both syntax and performance.


Push_back() vs Emplace_back()

Before discussing the performance differences, let’s discuss the syntax. Let’s create the following class to help us with our demonstration.

class A {
public:
    A(int param1, string param2) { 
        cout<<"Constructor Called\n"; 
    }

    A(const A &obj) { cout<<"Copy Constructor Called\n"; }
    ~A() { cout<<"Destructor called\n"; }
};

It contains 3 of the core methods that Classes can have. We haven’t done anything special in them, except for including a print statement which will let us know when any of the 3 methods are being called.

Throughout this tutorial we will experiment with adding objects of this Class to vectors with both push_back() and emplace_back().


Syntax

Here is the syntax for the push_back() method on vectors. We created an object of Class A with two random parameters, and passed it into the method.

vec.push_back(A(5, "Hello"));

The key takeaway here is that push_back() only accepts an object of type “A”. Now let’s compare this with emplace_back().

This is the syntax for emplace_back(). As you can see here, instead of passing in an object of Class A, we instead pass in the parameters that we would normally initialize Class A with.

vec.emplace_back(5, "Hello");

What’s happening here, is that these parameters are being “forwarded”. Normally, the object for A needs to be created, and then copied over into the vector. But with emplace_back() we directly create the object inside the vector.

This saves us one extra step. This point will become even more clear in the next section.


Comparing the differences

Now we will run the codes for both functions and compare the output.

int main() {
    vector<A> vec;

    cout << "#### PUSH BACK ####" << endl;
    vec.push_back(A(5, "Hello"));
}
#### PUSH BACK ####
Constructor Called
Copy Constructor Called
Destructor called
Destructor called

With push_back(), the (1) Constructor was called once for the creation of the object in main(). (2) Copy Constructor is called to copy the object from main() to the vector. (3 & 4) The main() function completes execution and both objects get destroyed and their destructors are called.

Now you can see here that there is alot of extra calls. Let’s see what happens with emplace_back().

int main() {
    vector<A> vec;

    cout << "\n#### EMPLACE BACK ####" << endl;
    vec.emplace_back(5, "Hello");
}
#### EMPLACE BACK ####
Constructor Called
Destructor called

Over here, we can see that only two calls were made. Only a single object was created inside the vector (not in main) and that object was destroyed once main() finished execution. So in total we saved two calls.


So what’s the key difference here? Well, in push_back(), we first created an object, and then duplicated this object into the vector. This involved an extra call to the copy constructor and destructor, which can be a little performance heavy in certain situations (when dealing with dynamic memory).

Can this duplication in push_back() be avoided? Well yes, it can. But that’s a separate topic entirely, called Move Semantics which allows us to “move” memory, instead of copying it. It has other benefits, other than just being used with push_back() so definitely check it out when you can.


Should we always use emplace_back() over push_back()?

Well, no. Not exactly.

emplace_back() is better performance wise, but there are certain scenarios where you might want to use push_back instead. For example, if you have a pre-existing object that you need to use even after pushing it to the vector (in other words, you need two copies of it). In this kind of scenario, emplace_back() cannot be used.

Another possible reason to use push_back() is that it’s compatible with pre C++11 compilers (emplace_back() is a newer feature).

If you really dig deep into it, there are a few more differences in the inner workings of these functions. But that’s a topic for another tutorial, or you can do your own research.


This marks the end of the C++ Vectors – push_back() vs emplace_back() Tutorial. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the tutorial content can be asked in the comments section below.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments