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
ref : http://egloos.zum.com/sweeper/v/3060229
반응형
'프로그래밍(Programming) > c++, 11, 14 , 17, 20' 카테고리의 다른 글
C++ 캐스팅 Static, Dynamic cast (0) | 2020.04.27 |
---|---|
std::remove_reference (0) | 2019.12.31 |
VS2017 C++ 17 활성화 옵션 (1) | 2018.05.14 |
Rvalue References: C++0x Features in VC10, Part 2 (0) | 2018.04.29 |
RVO(Return Value Optimization), NRVO(Named Return Value Optimization) (0) | 2018.04.28 |