When working with C++ Standard Template Library (STL) containers, two commonly used member functions for appending elements are push_back
and emplace_back
. While both serve the purpose of adding elements to containers like vectors, understanding their differences is crucial for optimizing performance.
Introduction
The methods push_back
and emplace_back
allow us to add new elements at the end of a container. However, they differ significantly in how they handle object creation and insertion, impacting performance, especially when dealing with complex data types or temporary objects.
push_back
The push_back
method is used to append an element to a container by copying or moving it. It comes in three overloads:
- By Const Reference:
void push_back(const Type& _Val);
- By Rvalue Reference:
void push_back(Type&& _Val);
The const reference overload is used for lvalues, while the rvalue reference overload utilizes move semantics to efficiently transfer ownership of objects.
emplace_back
emplace_back
, on the other hand, constructs an element directly in place at the end of a container. It uses perfect forwarding with variadic templates:
template<class... Args>
void emplace_back(Args&&... args);
This means that instead of creating a temporary object and then moving or copying it into the container, emplace_back
constructs the element directly in the storage space managed by the container using the provided arguments. This can eliminate unnecessary copies or moves.
Key Differences
-
Object Construction:
push_back
: Inserts a fully constructed object (copy/move).emplace_back
: Constructs the object in place with given constructor parameters.
-
Argument Handling:
push_back
takes either a const reference or an rvalue reference to an existing object.emplace_back
accepts variadic arguments, forwarding them to construct the object directly within the container.
-
Performance:
- For simple data types or when move semantics are sufficient, both methods may perform similarly.
- With complex objects or cases where temporary objects need construction (e.g., pairs in maps),
emplace_back
can be more efficient by avoiding extra copies or moves.
Practical Example
Consider adding a pair to a std::vector<std::pair<int, std::string>>
. Using push_back
, you create a pair and then copy it into the vector:
std::vector<std::pair<int, std::string>> vec;
vec.push_back(std::make_pair(1, "example"));
Using emplace_back
directly constructs the pair within the container:
vec.emplace_back(1, "example");
In this case, emplace_back
avoids creating a temporary std::pair
object, making it more efficient.
Use Cases
-
Temporary Objects: When you need to create and insert temporary objects into containers, prefer
emplace_back
. -
Complex Constructions: For classes with expensive copy/move constructors or destructors, use
emplace_back
to construct directly in the container. -
General Usage: In scenarios where simplicity outweighs performance concerns, either method can be used, but
emplace_back
offers greater flexibility and potential efficiency benefits.
Conclusion
Choosing between push_back
and emplace_back
depends on your specific needs regarding object construction and insertion into containers. While both methods achieve similar outcomes in terms of adding elements to a container, understanding their differences allows you to optimize for performance, particularly when dealing with complex data types or temporary objects. By leveraging the power of emplace_back
, you can write more efficient and expressive C++ code.