오늘은 vector에 원소를 추가할 때 사용하는 push_back과 emplace_back의 차이를 정리해보려고 한다.
두 함수는 모두 컨테이너의 끝에 원소를 추가한다는 점은 같지만 원소를 추가하는 방식에는 차이가 있다.
push_back: 이미 만들어진 객체를 추가한다.emplace_back: 생성자 인자를 받아 컨테이너 내부에서 객체를 직접 생성한다.
핵심 차이는 객체를 만들어서 넣느냐,
아니면 객체를 만들 인자를 넘겨서 내부에서 생성하느냐이다.
push_back
push_back은 이미 생성된 객체를 vector에 추가할 때 주로 사용한다.
std::vector<Test> v;
Test obj(10);
v.push_back(obj);
위 코드에서는 이미 만들어진 obj를 vector에 넣는다.
또한 임시 객체를 만들어서 넣을 수도 있다.
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_back 과 emplace_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_back과 emplace_back은 모두 vector의 끝에 원소를 추가하는 함수이다.
push_back
- 이미 만들어진 객체를 추가한다.
- 객체를 먼저 생성한 뒤 넣는 방식이다.
emplace_back
- 생성자 인자를 받아 내부에서 객체를 직접 생성한다.
- 생성자 인자를 직접 넘길 때 불필요한 임시 객체 생성이나 이동을 줄일 수 있다.
- 이미 만들어진 객체를 넘기는 경우에는
push_back과 큰 차이가 없을 수 있다.
마무리
push_back과 emplace_back은 둘 다 원소를 추가하는 함수이지만,
차이는 완성된 객체를 넣는지, 객체를 만들 인자를 넘기는지에 있다.
이미 만들어진 객체나 임시 객체를 넣는 경우에는 두 함수의 차이가 크지 않을 수 있고,emplace_back의 장점은 생성자 인자를 직접 넘길 때 가장 잘 드러난다.
앞으로는 무조건 emplace_back을 사용하기보다,
이미 객체가 만들어진 상황인지, 컨테이너 내부에서 바로 생성하고 싶은 상황인지에 따라push_back과 emplace_back을 구분해서 사용해야겠다.
'C++, CS' 카테고리의 다른 글
| [C++] std::find와 std::binary_search 차이 정리 (0) | 2026.05.06 |
|---|---|
| [C++] STL 컨테이너 정리 (0) | 2026.05.04 |
| [C++] map과 unordered_map 정리 (0) | 2026.04.30 |
| [C++] vector 와 list의 차이 정리 (0) | 2026.04.29 |
| [C++] 객체 복사를 막는 방법과 이유 (0) | 2026.04.28 |