본문 바로가기
C++

[C++] vector의 push_back, emplace_back 비교하기

by 소리쿤 2021. 12. 1.
template <class T> 
void std::vector<T>.push_back(T instance); 

template <class T, Args...> // 가변 인자 템플릿 
void std::vector<T>.emplace_back(T's Args...)
class Item // push_back, emplace_back 비교를 위한 클래스입니다. 
{ 
	public: int healAmount; 
	Item(int amount) : healAmount(amount) { cout << "일반 생성자 호출" << endl; }; 
	Item(const Item& rhs) : healAmount(rhs.healAmount) { cout << "복사 생성자 호출" << endl; }; 
	Item(Item&& rhs) : healAmount(move(rhs.healAmount)) { cout << "이동 생성자 호출" << endl; };
	~Item() { cout << "소멸자 호출" << endl; }; 
};

push_back() 수행 시

 

  1. Item(1000)을 통해 임시 객체 생성
  2. 복사 생성자를 통해 (위엔 이동 생성자가 정의돼있으므로 이동) push_back 함수에서 또 다른 임시 객체 생성
  3. vector의 끝에 요소 추가
  4. main의 임시 객체 삭제
  5. vector 내 임시 객체 삭제
int main() 
{ 
	vector<Item> items; 
	items.push_back(Item(1000)); 
}


emplace_back() 수행 시

 

  1. 1000을 emplace_back 함수에 넘김
  2. emplace_back 내부에서 임시 객체 생성
  3. vector 내 임시 객체 삭제
int main() 
{ 
	vector<Item> items; 
	items.emplace_back(1000); 
}


불필요한 복사를 막는다는 점에서 emplace_back이 상당히 우수해보인다.

하지만 우리는 emplace_back보다 push_back를 선호하며, 실제로 많이 사용한다.
그 원인은 push_back과 emplace_back의 생성자 차용 방식에 있다.

push_back은 명시적인 생성자를 호출하지만, (생성자가 없을 경우 컴파일 에러가 발생함)
emplace_back은 가변 매개변수 리스트를 받기 때문에 컴파일 타임에 타당한 생성자가 존재하는 지 알 수 없다.

다음 예제의 작성 의도는 2차원 벡터 vec의 첫 번째 요소에 10을 넣고자 하는 것이다.

push_back의 경우, 명시적으로 vector<T> 타입의 인자를 요구하기 때문에 타입이 맞지 않으면 컴파일 에러를 띄운다.

하지만 emplace_back의 경우 인자에 맞춰서 모든 생성자를 수행할 수 있다.
그렇기 때문에 컴파일 타임엔 저것이 맞는 지 틀리는 지도 알 수 없을 뿐더러, 위의 결과는 다음과 같이 나온다.


이와 같이 emplace_back은 이동 간의 비용을 절약해주지만 컴파일 타임에 모든 문제를 잡아낼 수 없다는
치명적인 리스크가 존재한다.

이동 작업의 cost가 방대한 경우가 아니라면 굳이 사용할 필요 없을 것 같다.
실제로 컴파일러의 최적화에 따라 push_back과 속도도 크게 차이나지 않는다고 한다.


 

https://gumeo.github.io/post/emplace-back/

 

emplace_back vs push_back | Gudmundur Blog&Bio

tl;dr emplace_back is often mistaken as a faster push_back, while it is in fact just a different tool. Do not blindly replace push_back by emplace_back, be careful of how you use emplace_back, since it can have unexpected consequences.

gumeo.github.io

 

'C++' 카테고리의 다른 글

[C++] deque, stack, queue, priority_queue  (0) 2021.12.02
[C++] vector와 list  (0) 2021.12.01
[C++] map과 unordered_map  (0) 2021.12.01