emplace 함수
std::emplace 함수는 STL 컨테이너( vector, list, set, map, deque 등 )에서 사용가능한, 새로운 원소를 삽입하는 함수입니다.
이와 비슷한 함수로 vector의 emplace_back, list의 emplace_front, emplace_back, map의 emplace_hine 등이 있지만,
함수의 필요에 따라, 필요한 인자를 더 받는 것으로, 동작하는 원리는 같습니다.
그리고, 원시 데이터( int, float 등 )를 처리하는 경우엔 insert와 emplace 함수와의 차이점은 없습니다.
하지만, 객체 데이터를 다루는 경우엔 사용하는 방법에 따라 차이가 있습니다.
이 함수가 insert나 push_back 등의 함수와 다른 점은 입력된 매개 변수를 사용해 내부 삽입을 수행하고,
그걸 통해서 불필요한 객체 복사를 방지한다는 점입니다.
그럼, 내부 삽입을 설명하기 위해서 먼저 클래스를 작성하겠습니다.
class CData{
int m_a;
string m_str;
public:
CData( int a, string str){ // 매개 변수 생성자
m_a = a;
m_str = str;
cout << "Parameter Constructor\n";
}
CData( const CData& other){ // 복사 생성자
m_a = other.m_a;
m_str = other.m_str;
cout << "Copy Constructor\n";
}
CData( CData&& other){ // 이동 생성자
m_a = other.m_a;
m_str = move(other.m_str);
cout << "Move Constructor\n";
}
};
이 클래스는 복사 생성자와 이동 생성자를 구현하고 있는 단순한 클래스입니다.
우선, 이 클래스의 객체를 vector에 넣는 과정을 보겠습니다.
int main(){
CData d(10, "test");
vector<CData> vec;
vec.reserve(10); // 재할당이 일어나는 것을 막으려고, 미리 메모리를 확보
vec.push_back(d);
vec.emplace_back(d);
return 0;
}
▼출력
Parameter Constructor
Copy Constructor
Copy Constructor
이 경우, 두 함수 모두 결과가 똑같습니다.
객체 d를 복사해서, vector에 복사한 객체를 삽입합니다.
그리고, 데이터 이동을 통해 원소를 추가하더라도, 두 함수의 차이는 없습니다.
vec.push_back( move(d)); // d -> move(d)
vec.emplace_back( move(d));
▼출력
Parameter Constructor
Move Constructor
Move Constructor
이 때도, 두 함수의 결과는 똑같습니다.
그러나, emplace 함수에선 객체에 생성에 필요한 데이터만으로 객체를 삽입할 수 있는 기능이 있습니다.
int main(){
vector<CData> vec;
vec.reserve(10); // 재할당이 일어나는 것을 막으려고, 미리 메모리를 확보
cout << "push_back\n";
vec.push_back( CData(10, "test"));
cout << "\nemplace\n";
vec.emplace_back( 10, "test");
return 0;
}
▼출력
push_back
Parameter Constructor
Move Constructor
emplace
Parameter Constructor
위의 결과가 보여주듯이, emplace는 매개 변수들을 받아서, 호출하고자 하는 생성자를 유추합니다
그래서, 내부에서 유추한 생성자를 통한 객체를 생성하고, 복사나 이동의 과정 없이 생성된 객체를 바로 컨테이너에 추가합니다.
이 과정이 위에서 말한 "내부 삽입"입니다.
반대로, push_back에는 이런 기능이 없습니다.
따라서, insert나 push_back 같은 원소를 추가하는 함수는 일반적으로 이동 과정이 더 필요하고,
만약, 이동 생성자를 구현하지 않아서 복사 생성자가 호출된다면, 두 함수 간의 성능 차이는 더 늘어나게 될 것입니다.
map에서 emplace 사용
map 컨테이너에서 emplace 함수를 사용하는 예제입니다.
int main(){
map< int, string> M;
M.insert( make_pair(1,"korea" )); // insert
M.emplace( 2, "america"); // emplace
for( auto& [key, value] : M ){
cout << key << ": " << value << endl;
}
return 0;
}
▼출력
1: korea
2: america
emplace함수를 사용하면, 따로 pair를 구성할 필요 없이, 바로 원소를 map에 추가할 수 있습니다.
list에서 emplace 사용
list 컨테이너에서 emplace 함수를 사용하는 예제입니다.
int main(){
list< pair<int, float> > li;
li.insert( li.begin(), make_pair(2, 3.5)); // insert
li.emplace( li.begin(), 3, 2.7); // emplace
for( const auto& x : li){
cout << x.first << ", " << x.second << endl;
}
return 0;
}
▼출력
3, 2.7
2, 3.5
이번에는 tuple 객체를 emplace 함수를 통해서 list에 저장하는 예제입니다.
#include <tuple>
int main(){
list< tuple<int, float, string> > li;
li.insert( li.begin(), make_tuple(2, 3.5, "insert"));
li.emplace( li.begin(), 3, 2.7, "emplace"); // tuple을 내부 생성
for( const auto& x : li){
cout << get<0>(x) << ", " << get<1>(x) << ", " << get<2>(x) << endl;
}
return 0;
}
▼출력
3, 2.7, emplace
2, 3.5, insert
위에서 보다시피, make_tuple 함수를 호출할 필요가 없습니다.
tuple의 사용법에 관한 글은 여기에서 볼 수 있습니다.
'C, C++ > 자료구조' 카테고리의 다른 글
[C++] std::vector의 resize와 reserve의 차이점 (0) | 2024.09.20 |
---|---|
[C++] STL map 사용법 (0) | 2024.06.27 |
[C++] 덱 ( deque ) 사용법 (0) | 2024.06.12 |
[C++] STL list 사용법 (0) | 2024.06.11 |
[C++] 우선 순위 큐 ( Priority Queue ) 사용법 (0) | 2024.06.10 |