(퍼온자료입니다. 출처 : http://egloos.zum.com/sweeper/v/3060229)
0. Variadic template
C++11의 emplace 함수에 생긴 큰 변화는 variadic template으로 인해 가능해졌다고 할 수 있다.
Variaidic template 페이지를 충분히 숙지한 이후 아래 내용을 읽어 나가면 훨씬 이해가 쉬울 것이다.
1. C++0x의 emplace 함수
VS2010까지의 emplace 함수들은 단순히 rvalue-reference를 인자로 받아 기존의 추가 함수를 호출하는 형식이었다,
// VS2010의 vector::emplace_back
void emplace_back(_Ty&& _Val)
{
// insert element at end
push_back(_STD forward<_Ty>(_Val));
}
template<typename _Valty>
void emplace_back(_Valty&& _Val)
{
// insert element at end
if (this->_Mylast == this->_Myend)
_Reserve(1);
_Orphan_range(this->_Mylast, this->_Mylast);
_Cons_val(this->_Alval, this->_Mylast, _STD forward<_Valty>(_Val));
++this->_Mylast;
}
즉, C++0x까지의 emplace 계열 함수는 외부에서 생성된 객체를 넘기는 방식이었기에,
emplace 계열 함수를 쓰더라도, 외부에서 객체 생성 -> 이동 -> 객체 파괴가 이루어졌던 것이다.
물론, 객체 생성 -> 복사 -> 객체 파괴보다는 성능상 이득이 있을 수 있다.
(이동을 어떻게 짰느냐에 따라...)
2. C++11의 emplace 함수
emplace 함수들이 variadic template으로 인해 진정한 emplace 계열 함수로 거듭나게 되었다.
// VS2013의 vector::emplace_back
template<typename... _Valty>
void emplace_back(_Valty&&... _Val)
{
// insert by moving into element at end
if (this->_Mylast == this->_Myend)
_Reserve(1);
_Orphan_range(this->_Mylast, this->_Mylast);
this->_Getal().construct(this->_Mylast, _STD forward<_Valty>(_Val)...);
++this->_Mylast;
}
C++11의 emplace 계열 함수는 객체 생성자의 인자들을 넘겨,
컨테이너 내부에서 생성 후 추가하는 방식을 사용하기에, 임시 객체를 아예 생기지 않게 하거나, 그 횟수를 줄일 수 있다.
우선 vector의 emplace_back 함수의 예제를 살펴보자. (cppreference.com의 예제 도용 ㅋ)
아래 예제에서는 임시 객체 생성을 완전히 회피할 수 있다.
#include <vector>
#include <string>
#include <iostream>
using namespace std;
struct President
{
string name;
string country;
int year;
President(string p_name, string p_country, int p_year)
: name(move(p_name)), country(move(p_country)), year(p_year)
{
cout << "I am being constructed.\n";
}
President(const President& other)
: name(move(other.name)), country(move(other.country)), year(other.year)
{
cout << "I am being copied.\n";
}
President(President&& other)
: name(move(other.name)), country(move(other.country)), year(other.year)
{
cout << "I am being moved.\n";
}
~President()
{
cout << "I am being destructed.\n";
}
President& operator=(const President& other) = default;
};
int main()
{
// VS2013의 emplace_back
// vector 내부에서 생성 -> 컨테이터에 추가하기에 임시 객체 생성 X
vector<President> elections;
elections.emplace_back("Nelson Mandela", "South Africa", 1994);
// VS2010의 emplace_back 역시 아래 push_back과 동일한 방식으로만 사용이 가능했었다
// 외부에서 생성 -> 벡터로 이동 -> 외부 객체 파괴가 발생한다
vector<President> reElections;
reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));
for (President const& president: elections)
{
cout << president.name << " was elected president of "
<< president.country << " in " << president.year << ".\n";
}
for (President const& president: reElections)
{
cout << president.name << " was re-elected president of "
<< president.country << " in " << president.year << ".\n";
}
}
std::map의 emplace 함수도 예제를 한번 살펴 보도록 하자.
아래 예제에서는 임시 객체가 한 번 덜 생성되는 것을 확인할 수 있다.
typedef map<int, President> ElectionMap;
ElectionMap elections;
////////////////////////////////////////////////////////////////////////////////
/// 기존의 insert
////////////////////////////////////////////////////////////////////////////////
{
// p 객체 생성
President p("Nelson Mandela", "South Africa", 1994);
// p 객체 복사 생성 for pair -> p 객체 이동
// 아래 두 문장은 동일하다
//elections.insert(ElectionMap::value_type(1, p));
elections.insert(make_pair(1, p));
// 이 스코프가 종료되면,
// President p("Nelson Mandela", "South Africa", 1994);에서 생성된 객체 파괴
// ElectionMap::value_type(1, p)에서 생성된 임시 객체 파괴
// map 소멸되면서 보관되어 있던 원소 파괴
}
////////////////////////////////////////////////////////////////////////////////
/// C++11의 emplace
////////////////////////////////////////////////////////////////////////////////
{
// President 객체 생성 -> 객체 이동 후 바로 컨테이너에 추가
elections.emplace(1, President("Nelson Mandela", "South Africa", 1994));
// 이 스코프가 종료되면
// President("Nelson Mandela", "South Africa", 1994)에서 생성된 객체 파괴
// map 소멸되면서 보관되어 있던 원소 파괴
}
참고로, 각 STL 컨테이너들이 지원하는 emplace 계열 함수들은 다음과 같다.
1) vector
-
emplace
-
emplace_back
2) deque / list
-
emplace
-
emplace_back
-
emplace_front
3) foward_list
-
emplace_front
-
emplace_after
4) set / map / unoreder_set / unordered_map
-
emplace
-
emplace_hint
'C++' 카테고리의 다른 글
C++11 람다 함수 (Lambda Function) (0) | 2020.04.26 |
---|---|
C++11 가변인자 템플릿 (Variadic template) (0) | 2020.04.12 |
C++11 enum class (1) | 2020.04.12 |
유니코드 문자열 처리 (0) | 2020.04.12 |
printf문의 서식지정자 (0) | 2020.04.12 |