여느때처럼 c++로 코딩을 하다 한가지 궁금점이 생겨났다.
궁금점의 시작은 젯브레인의 코드 리펙토링 메세지였다.
위 메세지는 vector
의 push_back()
함수 대신 emplace_back()
을 쓰는 것이 더 좋다는 내용의 조언이다.
해당 메세지는 vector
를 사용할 때에 자주보던 메세지여서, 아무 생각없이 emplace_back()
으로 수정하여 썻었는데, 문득 emplace_back()
은 push_back()
과 무슨 차이가 있길래 수정하여 쓰라는 것인지 궁금해져 정리해보게 되었다.
해당 두 함수는 vector
안에 객체를 넣는 방식에 차이가 있다고 한다.
결론부터 말하자면, push_back()
함수는 만들어진 객체를 집어넣는 형식이지만 emplace_back()
은 함수를 구성하는데에 필요한 정보를 넘겨주고 함수내에서 객체를 생성하여 삽입하는 방식이라고 한다.
말로만 들어선 이해하기 힘드니 예제 코드를 보며 이해해보자.
int main(){
vector<Item> m_vecItem;
std::cout << "excute push_back()" << "\n";
m_vecItem.push_back(Item(1));
}
[output]
excute push_back()
일반 생성자 호출
이동 생성자 호출
소멸자 호출
소멸자 호출
push_back()
을 통해 Item
객체를 삽입하기 위해
의 과정을 거치게 된다.
이제 emplace_back()
의 과정도 봐보자.
int main(){
vector<Item> m_vecItem;
std::cout << "excute emplace_back()" << "\n";
m_vecItem.emplace_back(1);
}
[output]
excute emplace_back()
일반 생성자 호출
소멸자 호출
emplace_back()
을 통해 Item
객체를 삽입하기 위해서는
의 과정을 거치게 된다.
이러한 과정을 봐보니 객체를 삽입할 때에 emplace_back()
을 사용하면 불필요한 객체 생성을 하나 줄일 수 있다는 것을 깨닳았다.
emplace_back()
과 push_back()
중 어느것이 더 효율적이다. 라고 말하기는 힘들지만, 두 함수의 차이점을 생각했을 때 다음과 같은 이슈가 발생할 수 있다.
int main(){
vector<vector<int>> v;
}
다음과 같이 v
가 이중 벡터로 되있는 경우 push_back()
를 사용하면 다음과 같이 데이터를 넣을 수 있다.
vector<int> v1 = { 1, 2 };
v.push_back(std::move(v1));
이 때 다음과 같이 데이터를 넣는 경우는 매칭되는 생성자가 없어 오류가 발생하게 된다.
v.push_back(10); // <- ERROR
하지만, emplace_back()
을 사용하면 오류가 발생하지 않게 된다.
v.emplace_back(10); // <- NOT ERROR
이는 v[0]
안에 10개의 새로운 공간을 할당하라는 뜻이기에 발생하는데, 이처럼 emplace_back()
은 컴파일 타임에서 에러를 잡아내지 못하기에 의도하지 않은 결과가 나올 수 있다.
하지만, emplace_back()
은 동일한 상황에서 이동 생성자를 호출하지 않는다는 장점이 있으므로, 이동 작업이 비쌀 경우에 사용하면 이점을 볼 수 있다.