C++ Programming
Software Development
Data Structures
Coding Best Practices
Vector Operations

push_back vs emplace_back

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

In modern C++ programming, efficiently adding elements to containers such as std::vector is crucial for performance-sensitive applications. Among the member functions that std::vector provides for inserting elements at the end of the container are push_back and emplace_back. Both perform similar tasks but in slightly different ways, each having implications on performance and usage. Understanding the differences between these two functions is valuable for writing optimal C++ code.

Understanding push_back

The push_back member function inserts a new element at the end of the vector, which is constructed from the provided argument. Essentially, push_back takes a single parameter of the type stored in the vector (or a type convertible to the type stored in the vector) and copies or moves it into the new element's location.

Let's see an example:

cpp
1#include <vector>
2#include <string>
3
4int main() {
5    std::vector<std::string> vec;
6    std::string str = "Hello";
7    vec.push_back(str); // Copies str into the vector
8    vec.push_back(std::string("World")); // Moves the temporary string into the vector
9}

In this example, push_back is called twice – first with a named object, which results in copying, and then with a temporary object, which results in moving.

Understanding emplace_back

Introduced in C++11, emplace_back attempts to optimize the process of constructing elements within containers by eliminating unnecessary copy or move operations. Unlike push_back, which constructs an object and then moves or copies it into the vector, emplace_back constructs the object directly in the location it will occupy in the vector.

Here’s how you might use emplace_back:

cpp
1#include <vector>
2#include <string>
3
4int main() {
5    std::vector<std::string> vec;
6    vec.emplace_back("Hello"); // Constructs the string directly in the vector's memory
7}

Here, the string "Hello" is constructed exactly where it needs to reside within the vector. This direct construction can lead to performance benefits, especially when dealing with complex data types.

Performance Comparison

The primary advantage of emplace_back over push_back is that it can construct objects in-place. This is particularly effective if the constructor of the object being added is expensive or if the object does not support moving efficiently but does support constructing with parameters directly.

Consider when a class has an expensive copy constructor or no move constructor defined, and the class has a constructor that accepts parameters for direct initialization:

cpp
1#include <vector>
2
3class BigObject {
4public:
5    BigObject(int data, double moreData) : data_(data), moreData_(moreData) {}
6    BigObject(const BigObject& other) : data_(other.data_), moreData_(other.moreData) {
7        // Expensive copy operation
8    }
9
10private:
11    int data_;
12    double moreData_;
13};
14
15int main() {
16    std::vector<BigObject> vec;
17    vec.push_back(BigObject(1, 3.14)); // Constructs and then copies
18    vec.emplace_back(1, 3.14); // Constructs in place
19}

Here, emplace_back avoids the extra copy, constructing the BigObject directly within the vector’s storage.

Summary Table

FunctionDescriptionUse Case
push_backCopies or moves the argument into the vector.Use when you already have an object.
emplace_backConstructs an object directly in the location within the container.Use when constructing an object from its arguments.

Conclusion

While push_back is suitable for adding elements that are already constructed, emplace_back provides a more efficient approach by constructing elements in place when possible. This makes emplace_back generally preferable when working with types that have expensive move or copy constructors or when the object can be constructed from arguments directly.

Choosing between these two functions ultimately depends on the specific use case and efficiency requirements of your application. When in doubt, profiling and measuring performance differences in a real-world context can provide insights into the best approach for your particular scenario.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.