Question

push_back vs emplace_back in C++: What’s the Difference?

cppc++11stdmove-semantics

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_back takes an object that already exists and appends it to the container.
  • emplace_back takes 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 a Type object.
  • emplace_back(...) can accept the constructor arguments for Type.

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_back when you already have an object
  • use emplace_back when you want to construct the object from arguments

Mental Model

Think of a container like an apartment building with empty rooms.

  • push_back means: bring in a finished piece of furniture and place it into the next room.
  • emplace_back means: 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.

Take Quiz

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:

  • name already exists
  • push_back(name) copies it into the vector
  • push_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::pair temporary 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:

  1. items is an empty vector of std::pair<int, std::string>.
  2. emplace_back(1, "pen") is called.
  3. The arguments 1 and "pen" are forwarded to the constructor of std::pair<int, std::string>.
  4. The pair is constructed directly in the vector's storage.
  5. 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:

  1. items is an empty vector.
  2. A temporary std::pair<int, std::string> is created from 1 and "pen".
  3. push_back receives that temporary as an rvalue.
  4. The vector moves that temporary into its storage.
  5. 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.

Take Quiz

Real Codebase Usage

In real projects, developers usually choose based on intent, not just micro-optimization.

Common style guideline

  • Use push_back(x) when x is 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

Featurepush_backemplace_back
What it takesAn existing object of the element typeConstructor arguments for the element type
Main purposeAdd an object you already haveConstruct object directly in the container
Can copy?YesYes, depending on arguments
Can move?YesYes, via perfect forwarding / constructor behavior
Avoids temporary object in some casesNot usuallyYes
Best forExisting valuesNew values built from parts
ReadabilityOften clearer when object already existsOften 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

  • insert can add elements at specific positions.
  • emplace_back only adds at the end.

emplace vs emplace_back

  • emplace constructs an element at a chosen position.
  • emplace_back is specialized for the end of the container.

Practical rule

  • Already have a value? Use push_back.
  • Have constructor arguments? Use emplace_back.
Take Quiz

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_back takes a T object.
  • emplace_back takes constructor arguments for T.
  • emplace_back is usually a variadic template.
  • emplace_back is most useful when constructing complex objects directly.
  • If an object already exists, push_back is often clearer.
  • emplace_back does 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.

Take Quiz

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 Book class with a title and page count.
  • Store multiple Book objects in a std::vector<Book>.
  • Use push_back with an already-created Book object.
  • Use emplace_back with constructor arguments.
  • Print all stored books to verify the result.
Take Quiz

Keep learning

Related questions

View more