Question
I am confused about the difference between push_back and emplace_back in C++.
void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);
Since push_back has an overload that accepts an rvalue reference, I do not understand the purpose of emplace_back. When should emplace_back be used instead of push_back?
Short Answer
By the end of this page, you will understand that push_back adds an existing object to a container, while emplace_back constructs the object directly inside the container. You will also see when the difference matters, when it does not, and how to choose the clearer option in real C++ code.
Concept
push_back and emplace_back are both used to add elements to the end of containers such as std::vector.
The key idea is this:
push_backtakes an object that already exists and appends it to the container.emplace_backtakes constructor arguments and builds the object directly inside the container.
Why push_back exists
With push_back, you first have a value of the element type, and then the container stores it.
std::vector<std::string> names;
std::string s = "Alice";
names.push_back(s); // copies s
names.push_back(std::move(s)); // moves s
Here, push_back works with an already-created std::string.
Why emplace_back exists
With emplace_back, you can pass the arguments that would be used to construct the object.
std::vector<std::string> names;
names.emplace_back("Alice");
Instead of creating a temporary std::string first and then moving it into the vector, emplace_back can construct the std::string directly in the vector's storage.
Why the rvalue push_back overload does not make emplace_back useless
This is the important distinction:
push_back(Type&&)still expects aTypeobject.emplace_back(...)can accept the constructor arguments forType.
For example:
std::vector<std::pair<int, std::string>> items;
items.push_back(std::pair<int, std::string>(1, "pen"));
items.emplace_back(1, "pen");
In the push_back version, a temporary std::pair<int, std::string> is created first, then moved into the vector.
In the emplace_back version, the pair is constructed directly inside the vector.
Why this matters
This matters because:
- it can avoid an extra temporary object
- it can be more expressive when you want to pass constructor arguments
- it can improve performance for some types
However, in many cases the performance difference is small or irrelevant, especially for simple or cheap-to-move types.
A subtle but important note
emplace_back is not always automatically better.
If you already have an object:
std::string s = "Alice";
names.emplace_back(s);
this still constructs the element from s, which may copy just like push_back(s) would. If the object already exists, push_back is often clearer.
A common rule of thumb:
- use
push_backwhen you already have an object - use
emplace_backwhen you want to construct the object from arguments
Mental Model
Think of a container like an apartment building with empty rooms.
push_backmeans: bring in a finished piece of furniture and place it into the next room.emplace_backmeans: bring in the parts and assemble the furniture directly inside the room.
If the furniture is already built, push_back makes sense.
If you still have the parts needed to build it, emplace_back can avoid building it somewhere else first and then carrying it in.
That is the real difference: existing object vs in-place construction.
Syntax and Examples
Core syntax
vec.push_back(value); // value is already a Type object
vec.push_back(Type(args...)); // temporary Type object, then moved
vec.emplace_back(args...); // constructs Type directly in the container
Example 1: push_back with an existing object
#include <vector>
#include <string>
int main() {
std::vector<std::string> names;
std::string name = "Alice";
names.push_back(name); // copy
names.push_back(std::move(name)); // move
}
Explanation:
namealready existspush_back(name)copies it into the vectorpush_back(std::move(name))moves it into the vector
Example 2: emplace_back with constructor arguments
#include <vector>
#include <string>
#include <utility>
int main() {
std::vector<std::pair<int, std::string>> items;
items.emplace_back(1, "pen");
items.emplace_back(2, "book");
}
Explanation:
- The vector stores
std::pair<int, std::string> emplace_back(1, "pen")forwards those arguments to the pair constructor- No separate
std::pairtemporary is required in source code
Example 3: similar result, different style
#include <vector>
#include <string>
#include <utility>
int main() {
std::vector<std::pair<int, std::string>> items;
items.push_back(std::pair<int, std::string>(1, "pen"));
items.emplace_back(2, "book");
}
Both lines add an element to the vector.
The difference is that emplace_back constructs from constructor arguments, while push_back receives a complete pair object.
Example 4: when emplace_back does not help much
std::vector<std::string> names;
std::string s = "Alice";
names.push_back(s);
names.emplace_back(s);
Both use the existing object s.
In this case, emplace_back does not provide the main benefit of in-place construction from raw constructor arguments.
Step by Step Execution
Consider this example:
#include <vector>
#include <string>
#include <utility>
int main() {
std::vector<std::pair<int, std::string>> items;
items.emplace_back(1, "pen");
}
Step by step:
itemsis an empty vector ofstd::pair<int, std::string>.emplace_back(1, "pen")is called.- The arguments
1and"pen"are forwarded to the constructor ofstd::pair<int, std::string>. - The pair is constructed directly in the vector's storage.
- The vector now contains one element:
{1, "pen"}.
Now compare with this:
#include <vector>
#include <string>
#include <utility>
int main() {
std::vector<std::pair<int, std::string>> items;
items.push_back(std::pair<int, std::string>(1, "pen"));
}
Step by step:
itemsis an empty vector.- A temporary
std::pair<int, std::string>is created from1and"pen". push_backreceives that temporary as an rvalue.- The vector moves that temporary into its storage.
- The temporary object is then destroyed.
The end result is the same, but the route is slightly different.
Important note: if the vector must reallocate because it runs out of capacity, existing elements may still need to be moved or copied regardless of whether you used push_back or emplace_back.
Real World Use Cases
Building container elements from multiple values
This is one of the best cases for emplace_back:
std::vector<std::pair<int, std::string>> products;
products.emplace_back(101, "Keyboard");
Useful when storing:
- pairs
- tuples
- structs or classes with several constructor arguments
Adding objects created elsewhere
If the object already exists, push_back is often the natural choice:
User user = loadUserFromDatabase();
users.push_back(std::move(user));
Parsing and collecting results
While reading a file or API response, you may build result objects directly in a container:
records.emplace_back(id, name, score);
This keeps code short and avoids explicit temporary objects.
Storing expensive-to-copy objects
For types that manage memory, file handles, or large buffers, constructing in place may avoid extra work.
Logging, metrics, and event collection
Applications often collect entries such as:
- timestamps and messages
- status codes and descriptions
- configuration records
These are commonly appended with emplace_back when entries are built from raw fields.
Real Codebase Usage
In real projects, developers usually choose based on intent, not just micro-optimization.
Common style guideline
- Use
push_back(x)whenxis already an object. - Use
emplace_back(args...)when you want to build the object in the container.
This makes code easier to read.
Example: parsing data into objects
struct Product {
int id;
std::string name;
double price;
Product(int id, std::string name, double price)
: id(id), name(std::move(name)), price(price) {}
};
std::vector<Product> products;
products.emplace_back(10, "Mouse", 19.99);
This pattern is common in:
- CSV parsing
- API response mapping
- database row conversion
Example: guard clauses before insertion
if (name.empty()) {
return;
}
products.emplace_back(id, name, price);
Validation often happens first, then an object is appended.
With move-only types
For move-only types such as std::unique_ptr, both can be used depending on what you have:
std::vector<std::unique_ptr<int>> values;
values.push_back(std::make_unique<int>(5));
// or
values.emplace_back(std::make_unique<int>(6));
A more direct approach is often:
values.emplace_back(new int(7));
But in modern C++, std::make_unique is usually preferred for clarity and safety when possible.
Readability matters
In large codebases, emplace_back can sometimes hide which constructor is being called. If constructor arguments are ambiguous or surprising, creating the object explicitly first can be clearer.
Common Mistakes
Mistake 1: thinking emplace_back is always faster
Not always.
If you already have an object, emplace_back may offer no real advantage:
std::string s = "Alice";
names.push_back(s);
names.emplace_back(s);
These can both copy from s.
Mistake 2: using emplace_back when push_back is clearer
Less clear:
std::string s = "Alice";
names.emplace_back(std::move(s));
Clearer:
std::string s = "Alice";
names.push_back(std::move(s));
If you already have a std::string, push_back expresses that directly.
Mistake 3: assuming no moves ever happen
Even with emplace_back, vector reallocation may move or copy existing elements when capacity grows.
std::vector<std::string> names;
for (int i = 0; i < 1000; ++i) {
names.emplace_back("item");
}
New elements are constructed in place, but old elements may still be relocated during growth.
Mistake 4: accidentally calling an unexpected constructor
emplace_back forwards arguments directly to constructors. That can call a constructor you did not intend.
std::vector<std::vector<int>> data;
data.emplace_back(5, 1); // creates vector<int> with 5 elements, each equal to 1
A beginner might wrongly expect this to add the two integers 5 and 1.
Mistake 5: believing the signatures shown are the full story
emplace_back is usually a variadic template, more like:
template<class... Args>
reference emplace_back(Args&&... args);
That is why it can accept constructor arguments of many shapes, not just a single Type&&.
Mistake 6: overusing std::move
Broken thinking:
names.push_back(std::move("Alice"));
String literals are not std::string objects. Just write:
names.emplace_back("Alice");
// or
names.push_back(std::string("Alice"));
Use std::move on named objects when you want to transfer from them.
Comparisons
| Feature | push_back | emplace_back |
|---|---|---|
| What it takes | An existing object of the element type | Constructor arguments for the element type |
| Main purpose | Add an object you already have | Construct object directly in the container |
| Can copy? | Yes | Yes, depending on arguments |
| Can move? | Yes | Yes, via perfect forwarding / constructor behavior |
| Avoids temporary object in some cases | Not usually | Yes |
| Best for | Existing values | New values built from parts |
| Readability | Often clearer when object already exists | Often concise when constructing on insert |
push_back(temp) vs emplace_back(args...)
items.push_back(std::pair<int, std::string>(1, "pen"));
items.emplace_back(1, "pen");
These often produce similar results, but emplace_back expresses direct construction.
insert vs emplace_back
insertcan add elements at specific positions.emplace_backonly adds at the end.
emplace vs emplace_back
emplaceconstructs an element at a chosen position.emplace_backis specialized for the end of the container.
Practical rule
- Already have a value? Use
push_back. - Have constructor arguments? Use
emplace_back.
Cheat Sheet
// If you already have an object:
vec.push_back(obj); // copy
vec.push_back(std::move(obj)); // move
// If you want to build the object in place:
vec.emplace_back(arg1, arg2, arg3);
Quick rules
push_backtakes aTobject.emplace_backtakes constructor arguments forT.emplace_backis usually a variadic template.emplace_backis most useful when constructing complex objects directly.- If an object already exists,
push_backis often clearer. emplace_backdoes not prevent vector reallocations.
Good examples
std::vector<std::string> v;
v.emplace_back("hello");
std::string s = "world";
v.push_back(s);
v.push_back(std::move(s));
Common pattern
std::vector<std::pair<int, std::string>> items;
items.emplace_back(1, "pen");
Be careful
std::vector<std::vector<int>> data;
data.emplace_back(5, 1); // vector of five 1s, not {5, 1}
FAQ
Is emplace_back always better than push_back?
No. It is better when you want to construct an element directly from constructor arguments. If you already have an object, push_back is often clearer.
Does push_back with an rvalue do the same thing as emplace_back?
Not exactly. push_back with an rvalue still receives a fully constructed object. emplace_back can build that object inside the container from constructor arguments.
Is emplace_back always faster?
No. It can avoid a temporary in some situations, but the difference may be tiny. Readability and correctness are usually more important.
Can emplace_back still copy or move objects?
Yes. It depends on the constructor and the arguments you pass. Also, container reallocation may move or copy existing elements.
Should I replace every push_back with emplace_back?
Usually no. Use push_back when you already have the object. Use emplace_back when constructing during insertion.
Why can emplace_back(1, "text") work for a pair?
Because emplace_back forwards those arguments to the constructor of the element type, such as std::pair<int, std::string>.
What is the real signature of emplace_back?
In standard library containers, it is typically a variadic template like template<class... Args> reference emplace_back(Args&&... args);. That is what allows flexible constructor forwarding.
Mini Project
Description
Build a small C++ program that stores Book objects in a std::vector and compares inserting existing objects with constructing objects directly in the vector. This demonstrates the practical difference between push_back and emplace_back using a custom class.
Goal
Create and append Book objects using both push_back and emplace_back, and understand which one is appropriate in each case.
Requirements
- Create a
Bookclass with a title and page count. - Store multiple
Bookobjects in astd::vector<Book>. - Use
push_backwith an already-createdBookobject. - Use
emplace_backwith constructor arguments. - Print all stored books to verify the result.
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.