
Return Value Optimization 이하 RVO 및, Named RVO(NRVO) 와 Copy-Elision 은 C++98 시절부터 도입됬으며, 런타임 퍼포먼스를 향샹시키는 기능을 한다.
// Example.1 RVO
#include <iostream>
using namespace std;
struct Rain { // Note: All methods have side effects
Rain() { cout << "c'tor" << endl; }
~Rain() { cout << "d'tor" << endl; }
Rain(const Rain&) { cout << "copy c'tor" << endl; }
Rain(Rain&&) { cout << "move c'tor" << endl; }
Rain& operator=(const Rain&) {
cout << "copy assignment" << endl;
return *this;
}
Rain& operator=(Rain&&) {
cout << "move assignment" << endl;
return *this;
}
};
Rain rvo() {
return Rain();
}
auto main() ->int {
Rain shit = rvo();
}
// 출력결과 with RVO
// c'tor
// d'tor
// 출력결과 without RVO
// c'tor
// move c'tor
// d'tor
// move c'tor
// d'tor
// d'tor
- Return Value Optimization (RVO)
- RVO는 리턴 값으로 temporary object를 생성하여 반환하지 않는 것을 목표로 한다. 그러나 부작용도 존재한다.
- 일반적인 컴파일러들은 디폴트로 RVO를 사용하는 것으로 설정되어 있으며, RVO가 없을시, 예제 코드에서 컴파일러는 세 개의 Rain 오브젝트를 생성하게 된다.
- rvo() 안에 있는 temporary object -> c*tor
- main() 안에 있는 temporary object -> 첫번째 move c'tor
- shit 이라고 하는 named object -> 두번째 move c'tor
- RVO는 C++ ABI 차원에서 탑제되었으므로, 비활성화하는 것이 매우 어렵다.
// Example.2 NRVO
Rain rvo() {
Rain brain;
return brain;
}
auto main() ->int {
rvo();
}
// 출력결과 with NRVO
// c'tor
// d'tor
// 출력결과 without NRVO
// c'tor
// move c'tor
// d'tor
// d'tor
- Named Return Value Optimization (NRVO)
- NRVO는 이름을 가진 객체가 반환 되었음에도, 복사되지 않는 것을 의미한다.
- 일반적으로 RVO가 활성화되어 있는 환경에서는 NRVO가 좀처럼 나타나지 않는다.
// Example.3 Copy Elision
void foo(Rain s) {
}
auto main() ->int {
foo(Rain());
}
// 출력결과 Copy Elision
// c'tor
// d'tor
- Copy Elisioin
- Copy Elision은 RVO처럼 리턴값에 국한되지 않는다. RVO는 Copy Elision의 범주에 속하며, 복사를 피한다는 본질적인 개념은 같다.
- RVO가 일어나지 않는 상황
- Deciding on Instance at Runtime
- 컴파일러가 함수내의 어떤 인스턴스를 반환할지 모르는 경우
- Returning a Parameter / Global
- 스코프를 벗어난 객체를 반환할 경우
- Returning by std::move()
- 이 글에서 설명하기에는 복잡한 부분 (참고)
- Assignment
- RVO는 리턴값에서 객체가 생성된 경우에만 발생할수 있으므로, 복사/이동 생성자 대신에 operator=를 사용하는 경우에는 발생하지 않는다.
- Returning Member
- Deciding on Instance at Runtime
// Deciding on Instance at Runtime
Rain RainDrop(bool drop_top) {
Rain a, b;
if (drop_top) {
return a;
}
else {
return b;
}
}
auto main() ->int {
Rain rain = RainDrop(true);
}
// 출력결과
// c'tor
// c'tor
// move c'tor
// d'tor
// d'tor
// d'tor
// Returning a Parameter / Global
Rain global_rain;
Rain RainDrop(Rain drop) {
return drop;
}
Rain RainGlobal() {
return global_rain;
}
auto main() ->int {
// case 1
Rain rain = RainDrop(global_rain);
// case 2
Rain rain2 = RainGlobal();
}
// case 1
// c'tor
// copy c'tor
// move c'tor
// d'tor
// d'tor
// d'tor
// case 2
// c'tor
// copy c'tor
// d'tor
// d'tor
// Returning by std::move()
Rain RainDrop() {
Rain rain;
return std::move(rain);
}
auto main() ->int {
Rain drop = RainDrop();
}
// 출력결과
// c'tor
// move c'tor
// d'tor
// d'tor
// Assignment
Rain RainDrop() {
return Rain();
}
auto main() ->int {
Rain drop = RainDrop();
drop = RainDrop();
}
// 출력결과
// c'tor
// c'tor
// move assignment
// d'tor
// d'tor
// Returning Member
struct RainWrapper{
Rain rain;
};
Rain RainDrop() {
return RainWrapper().rain;
}
auto main() ->int {
Rain drop = RainDrop();
}
// 출력결과
// c'tor
// move c'tor
// d'tor
// d'tor
'C++' 카테고리의 다른 글
Template 가이드라인 (0) | 2022.07.04 |
---|---|
Type Category Testing_1(형 카 검-내장타입) (0) | 2022.07.03 |
std::exception과 Stack Unwinding 과 RAII (0) | 2020.12.04 |
[레거시 코드] 함수포인터, 보이드포인터 (0) | 2020.12.03 |
[C++] 범위기반 for 루프를 위한 클래스 템플릿 최소 구현 (0) | 2020.11.16 |