C++, CS

[C++] push_back과 emplace_back의 차이

dhlee-dev 2026. 5. 1. 20:37

오늘은 vector에 원소를 추가할 때 사용하는 push_backemplace_back의 차이를 정리해보려고 한다.

두 함수는 모두 컨테이너의 끝에 원소를 추가한다는 점은 같지만 원소를 추가하는 방식에는 차이가 있다.

  • push_back : 이미 만들어진 객체를 추가한다.
  • emplace_back : 생성자 인자를 받아 컨테이너 내부에서 객체를 직접 생성한다.

핵심 차이는 객체를 만들어서 넣느냐,
아니면 객체를 만들 인자를 넘겨서 내부에서 생성하느냐이다.


push_back

push_back은 이미 생성된 객체를 vector에 추가할 때 주로 사용한다.

std::vector<Test> v;

Test obj(10);
v.push_back(obj);

위 코드에서는 이미 만들어진 objvector에 넣는다.

또한 임시 객체를 만들어서 넣을 수도 있다.

v.push_back(Test(10));

이 경우에는 Test(10) 임시 객체가 먼저 생성되고,
이동 생성자가 있다면 그 객체가 vector 내부로 이동된다.

즉, push_back은 기본적으로 생성된 객체를 받아서 추가하는 방식이다.


emplace_back

emplace_back은 생성자 인자를 받아
vector 내부에서 객체를 직접 생성하는 가변 인자 템플릿 함수이다.

std::vector<Test> v;

v.emplace_back(10);

위 코드에서는 10을 이용해 vector 내부에서 바로 Test 객체를 생성한다.

따로 Test(10) 임시 객체를 만든 뒤 넣는 것이 아니라,
컨테이너가 관리하는 메모리 공간 안에서 객체를 직접 생성할 수 있다.


push_backemplace_back 차이 예제

#include <iostream>
#include <vector>

class Test {
public:
    Test() {
        std::cout << "생성\n";
    }

    Test(int num) {
        std::cout << "인자 생성\n";
        data = num;
    }

    Test(float num) {
        std::cout << "float 인자 생성\n";
        data = num;
    }

    Test(const Test&) {
        std::cout << "복사 생성\n";
    }
    Test& operator=(const Test&) {
        std::cout << "복사 대입\n";
        return *this;
    }

    Test(Test&&) noexcept {
        std::cout << "이동 생성\n";
    }

    Test& operator=(Test&&) noexcept {
        std::cout << "이동 대입\n";
        return *this;
    }

private:
    int data = 0;
};

int main() {
    std::vector<Test> v;
    v.reserve(20);    // vector에 원소 추가 시 재할당을 막기 위함

    std::cout << "---임시 객체 전달---\n";
    v.push_back(Test());
    v.emplace_back(Test());
    std::cout << "\n";

    std::cout << "---생성자 인자 전달---\n";
    v.push_back(10);
    v.emplace_back(10);
    std::cout << "\n";

    std::cout << "---외부 객체 전달---\n";
    Test t1, t2;
    std::cout << "\n";

    v.push_back(t1);
    v.emplace_back(t2);
    std::cout << "\n";

    std::cout << "---std::move() 전달---\n";
    v.push_back(std::move(t1));
    v.emplace_back(std::move(t2));
}

결과

---임시 객체 전달---
생성
이동 생성
생성
이동 생성

---생성자 인자 전달---
인자 생성
이동 생성
인자 생성

---외부 객체 전달---
생성
생성

복사 생성
복사 생성

---std::move() 전달---
이동 생성
이동 생성
v.push_back(Test());
v.emplace_back(Test());

이렇게 Test()처럼 임시 객체를 넘길 경우엔 push_back, emplace_back 둘 다
이동이 가능하면 이동 생성으로 처리하는 것을 확인할 수 있다.

v.push_back(10);
v.emplace_back(10);

생성자 인자를 직접 넘기는 경우,
push_back(10)10을 이용해 Test 임시 객체를 만든 뒤 그 객체를 vector 내부로 이동한다.

반면 emplace_back(10)10을 생성자 인자로 전달해
vector 내부에서 바로 Test 객체를 생성하는 차이를 볼 수 있다.

Test t1, t2;

v.push_back(t1);
v.emplace_back(t2);

t1, t2처럼 이름이 있는 외부 객체를 전달하면 push_back, emplace_back 둘 다 복사생성을 수행한다.

v.push_back(std::move(t1));
v.emplace_back(std::move(t2));

마지막으로 std::move()를 이용해 이동 가능한 형태로 넘기면
임시 객체와 마찬가지로 이동이 가능할 때 이동 생성 처리를 수행한다.


정리

push_backemplace_back은 모두 vector의 끝에 원소를 추가하는 함수이다.

push_back

  • 이미 만들어진 객체를 추가한다.
  • 객체를 먼저 생성한 뒤 넣는 방식이다.

emplace_back

  • 생성자 인자를 받아 내부에서 객체를 직접 생성한다.
  • 생성자 인자를 직접 넘길 때 불필요한 임시 객체 생성이나 이동을 줄일 수 있다.
  • 이미 만들어진 객체를 넘기는 경우에는 push_back과 큰 차이가 없을 수 있다.

마무리

push_backemplace_back은 둘 다 원소를 추가하는 함수이지만,
차이는 완성된 객체를 넣는지, 객체를 만들 인자를 넘기는지에 있다.

이미 만들어진 객체나 임시 객체를 넣는 경우에는 두 함수의 차이가 크지 않을 수 있고,
emplace_back의 장점은 생성자 인자를 직접 넘길 때 가장 잘 드러난다.

앞으로는 무조건 emplace_back을 사용하기보다,
이미 객체가 만들어진 상황인지, 컨테이너 내부에서 바로 생성하고 싶은 상황인지에 따라
push_backemplace_back을 구분해서 사용해야겠다.