C++ difference between emplace_back and push_back function

In this post we will discuss the difference between push_back and emplace_back function in C++.

Although C++ emplace_back and push_back functions sole purpose is to append data at the end of the vector,their exists some differences between them.And one of the petty differences which might be worth mentioning is push_back function has been part of the Standard C++ from the time of its creation, the emplace_back function, however, is a new addition to the language. It is added recently under C++11 features.

If you are new to C++ and not familiar with either of the functions, please read about them first. This post only explains the differences the between emplace_back and push_back functions. I won’t be explaining here on how to use them.

LInk :Vector push_back function


Difference 1: push_back accepts the only object of the type if the constructor accept more than one arguments, whereas emplace_back accept arguments of the constructor of the type.

When the vector type is a user-defined type: class or structure, and the constructor of the type accepts more than one argument, in such case calling the push_back function requires that we pass an object of the type. But in calling the emplace_back we can simply pass the arguments of the type of the constructor instead of passing the object itself.

Note this difference arises only when the constructor accepts more than one argument. In constructor accepting only one argument when calling the push_back we can pass the argument of the type of the constructor instead of passing the object. This acceptance of raw data -instead of object- in push_back for one argument constructor is due to the C++11 version of push_back function. The C++11 version allows construction of object from the argument passed which is then pushed into the vector container.

If the constructor accepts two or more arguments you must pass the object of the type explicitly.

Code example:For class with constructor accepting one argument.

class Test
{
int i ;

public:
Test(int ii):i(ii) { } //constructor

int get const() { return i; }

~Test( ) { }
};

int main( )
{
vector<int> vec={ 21 , 45 };

vec.push_back( Test(34) ) ; //Appending Test object by passing Test object

vec.push_back( 901 ) ; //Appending Test object but int data is passed,work fine

vec.emplace_back( Test(7889) ); //work fine

vec.emplace_back( 4156 ) ; //work fine

for( auto elem:vec )
{
cout<< elem.get() << ” ” ;
}

cin.get( );
return 0;
}

Output

21 45 34 901 7889 4156

Here is another code example when the constructor accepts two arguments.

Code example:Class with constructor accepting two arguments

class New
{
int i;
string st;
public:
New(int ii, string s):i(ii) , st(s) { }

int getInt const() { return i; }

string getString const () { return st; }

~New( ) { }
};

int main( )
{
vector<int> vec={ {21,”String”} , New{45 , “tinger”} } ;

vec.push_back( New(34 , “Happy” ) ) ; //Appending Test object

vec.push_back( 901 , “Doer” ) ; //Error!!

vec.emplace_back( New(78 , “Gomu gomu” ) ); //work fine

vec.emplace_back( 41 , “Shanks” ) ; //work fine

for( auto elem:vec )
{
cout<< elem.getInt( ) << ” ” << elem.getString( ) << endl ;
}

cin.get( ) ;
return 0 ;
}

Output

21 String
45 Tinger
34 Happy
78 Gomu gomu
41 Shanks

The first push_back call (line 19) succeeds because we have passed a ‘New’ object, but the second push_back call (line 21) fails because the push_back simply cannot accept two arguments. The emplace_back on the other hand happily accept the two arguments(line 25) passed to it.

In receiving the arguments the emplace_back create an object of New by calling the constructor and append the object to the vector and so the call succeeds.

The bottom line is if you use push_back and the type is ‘class’ or ‘struct’ with constructor accepting one argument then you can pass the data of the class instead of passing the object explicitly. But, if the class constructor accept more than one argument you are only allowed to pass the object of the class.

In emplace_back function however whether the class accepts one or more arguments you can pass the object or the data of the type accepted by the constructor of the class, either way, it works fine. My advice is you should prefer emplace_back over push_back function usage.



Difference 2:Efficiency

The word ‘efficiency’ can have different meanings here we will look at it as having faster working code: producing lesser overhead. First, let us see when the vector type is a built-in type and then we will see for the user defined-type.

built-in type

If the type is a built-in type there is no difference in efficiency between push_back and emplace_back function.

User-defined type

If the vector type is a class or a structure i,e. a user-defined type then in such case the emplace_back is more efficient than the push_back function, why and how?

push_back call when type is user-defined type

If we try to append the object directly (before the object is created) to the vector using push_back, then in this process a temporary object is created first. While creating the temporary object three steps occur:
 
i)A constructor is called to create the temporary object.
 
ii)A copy of the temporary object is then created in the vector.
 
iii)After copying the object the destructor is called to destroy the temporary object.

The verification of the three processes occurring when push_back is called is shown at the bottom of this post, inside the ‘Side Note’ section.

emplace_back call when type is user-defined type

If emplace_back is used the temporary object is not created instead the object is created directly in the vector. The extraneous creation of the temporary object is avoided with emplace_back. Hence the performance is enhanced.

Consider the code below.

class Dat
{
int i;

public:
Dat(int ii):i(ii) { }

~Dat( ) { }
};

vector<Dat> vec ;

vec.push_back( Dat(89) ); //efficiency lesser

vec.push_back( 67 ); //Same as above efficiency is lesser

vec.emplace_back( 890 ); //efficiency more

In the first push_back call(line 13) and second push_back call(line 15) the three steps discuss above occur and hence the performance is reduced.

In the emplace_back call only the first step occur and so the performance is enhanced.

class Bat
{
int i ;
string ss ;
char c ;

public:
Dat(int ii , string s, char cc):i(ii) , ss(s) , c(cc) { }

~Dat( ) { }
};


vector<Bat> b1( 23 , "S" ,  'd');

push_back( b1 ); //Perforamce same as below

empalce_back( 34 , "New" , 'D' ); //Perforamce same as above

push_back( b2(90 , "String" , 'P') ); //Perforamce lesser

emplace_back( 890 , "true" , 'O' ); //No change in performance

The first push_back call(line 16) we are simply passing the object that was already created so no temporary object creation is needed, hence the performance is same as the emplace_back call.

In the second push_back call (line 20) there is a need for temporary object creation hence lesser efficiency.

The pictorial representation below might help you understand better.

C++ difference between emplace_back and push_back

The copying process is omitted in emplace_back function call.


Side note

Verifying that the three steps occur when push_back is called.Consider the class as shown below.

class A{
public:
 A() { cout<<"A constructor called!!"; }
 ~A() { cout<<"\nA destructor called!!"; }
 };

int main()
{
vec<A>v ; 

v.push_back( 78 );

/** or 
v.psuh_back( A(890) ); //The output will be same 
***/

cin.get();
retrun 0;
}

If you run the program you will get the output as;

A constructor called!!
A destructor called!!

The constructor is called to create the temporary object. The temporary object is then copied to the vector storage.Finally to destroy the temporary object the destructor is called. Which is confirmed by the program output.

Now if you run the program using emplace back, say the code example given below.

v.emplace_back( 23 );

The output in this case is,

Constructor called

No destructor is called here.




Leave a Reply

Your email address will not be published. Required fields are marked *