한글 번역
title: “Tip of the Week #112: emplace vs. push_back”
layout: tips
sidenav: side-nav-tips.html
published: true
permalink: tips/112
type: markdown
order: “112”
—
원래 게시 날짜: 2016-02-25, totw/112
작성자: Geoff Romer (gromer@google.com)
개정일: 2017-08-30
“우리가 힘을 덜 사용할수록, 우리의 힘은 더 커질 것이다.” — 토머스 제퍼슨
C++11은 컨테이너에 항목을 삽입하는 강력한 새로운 방법을 도입했습니다: emplace
메서드입니다. 이 메서드는 객체의 생성자를 사용하여 컨테이너 내부에서 객체를 바로 생성할 수 있도록 합니다. 여기에는 이동 및 복사 생성자도 포함되므로, push
나 insert
메서드를 사용할 수 있는 곳이면 어디든지 emplace
메서드도 동일하게 사용할 수 있습니다:
std::vector<string> my_vec;
my_vec.push_back("foo"); // OK, 그래서...
my_vec.emplace_back("foo"); // 이것도 OK, 결과는 동일
std::set<string> my_set;
my_set.insert("foo"); // 여기서도 동일: insert 호출을
my_set.emplace("foo"); // emplace 호출로 변경 가능.
이것은 당연히 다음과 같은 질문을 제기합니다:
어떤 것을 사용해야 할까요?
차라리 push_back()
과 insert()
를 완전히 버리고 항상 emplace
메서드를 사용하는 것이 좋을까요?
이 질문에 답하기 위해 다른 질문을 해보겠습니다: 아래 두 줄의 코드가 각각 무엇을 할까요?
vec1.push_back(1<<20);
vec2.emplace_back(1<<20);
첫 번째 줄은 매우 간단합니다: 숫자 1048576
을 벡터의 끝에 추가합니다.
하지만 두 번째 줄은 명확하지 않습니다. 벡터의 타입을 모르면 어떤 생성자를 호출하는지 알 수 없으므로 이 코드가 무엇을 하는지 확실히 말할 수 없습니다.
예를 들어, vec2
가 std::vector<int>
라면 첫 번째 줄과 동일하게 1048576
을 끝에 추가합니다.
그러나 vec2
가 std::vector<std::vector<int>>
라면, 이 코드는 100만 개 이상의 요소를 가진 벡터를 생성하며, 메모리를 수 메가바이트 할당할 수 있습니다.
더 명확한 표현으로 push_back()
선택
따라서 동일한 인수로 push_back()
과 emplace_back()
을 모두 사용할 수 있다면, push_back()
을 선택하면 코드의 의도가 더 명확해집니다.
또한 push_back()
은 더 안전합니다. 예를 들어, std::vector<std::vector<int>>
에서 첫 번째 벡터에 숫자를 추가하려 하지만 실수로 첨자를 생략했다고 가정해 봅시다.
my_vec.push_back(2<<20); // 컴파일 오류 발생 → 문제를 쉽게 발견
my_vec.emplace_back(2<<20); // 컴파일됨 → 런타임에 문제 발견
emplace_back()
의 성능 이점
물론, 암시적 변환이 포함된 경우 emplace_back()
이 push_back()
보다 약간 더 빠를 수 있습니다. 예를 들어:
my_vec.push_back("foo");
위 코드는 문자열 리터럴에서 임시 string
객체를 생성한 뒤 이를 컨테이너에 이동시킵니다.
반면,
my_vec.emplace_back("foo");
는 컨테이너 내부에서 string
객체를 직접 생성하여 추가 이동을 방지합니다.
비용이 큰 타입에서는 emplace_back()
을 사용하는 것이 성능상 더 나을 수 있습니다.
그러나 성능 차이가 미미한 경우도 많으며, 대부분의 경우 코드의 가독성과 안전성을 해치는 “최적화”는 피해야 합니다.
일반적인 권장 사항
일반적으로, 동일한 인수로 push_back()
과 emplace_back()
을 모두 사용할 수 있다면, push_back()
을 선호하십시오.
마찬가지로 insert()
와 emplace()
도 동일합니다.
성능 차이가 실제로 애플리케이션 벤치마크에서 눈에 띄는 경우에만 emplace
를 사용해 최적화를 고려하십시오.