Study/C & C++

[C++] 복사 생성자와 RVO, NRVO

게임 만드는 나무꾼 2022. 9. 19. 16:24

01. 복사 생성자란?

  • 같은 타입의 인스턴스를 매개변수로 받는 생성자를 의미한다. 
class A
{
public:
	A() {};
    A(const A& a){}; // Copy Constructor
};

02. 복사 생성자가 호출되는 경우

복사 생성자가 호출되는 경우는 세 가지이다.

  1. 기존 생성 객체를 사용해 새로운 객체를 초기화하는 경우
  2. Call-By-Value 형식으로 함수의 매개변수를 전달할 때
  3. Value 형태로 함수에서 return할 때
A origin;

// 1.
A copy(origin);
A copy1 = origin;

// 2.
void Copy(A a)
{
	// do something
}

// 3.
A Copy2()
{
	return A();
}

 

그렇다면, 아래 코드의 결과는 어떨까?

#include <iostream>

class A
{
public:
	A()
	{
		std::cout << this << " Constructor Called\n";
	}

	A(const A& a)
	{
		std::cout << this << " Copy Constructor Called\n";
	}

	~A()
	{
		std::cout << this << " Destructor Called\n";
	}
};

A Copy(A origin)
{
	return A(origin);
}

int main() 
{
	A origin;
	A c1 = Copy(origin);
}

위에서 말한 복사 생성자 호출 조건에 따르면 복사 생성자는 총 3번 불려야 한다.

  1. Copy() 함수의 매개변수 origin이 생성되며 한 번
  2. return값으로 전달되는 임시 객체를 생성하며 한 번
  3. c1의 복사 생성자가 호출되며 한 번

그러나 실제로 Visual Studio로 실행해보면 Copy Constructor는 두 번 호출된다. 이는 RVO라는 컴파일러 최적화 기법 때문이다.

RVO (Return Value Optimization)은 C++11부터 공식화된 기능으로, 불필요한 복사를 컴파일러가 최소화한다.

RVO가 적용되면 위 코드에서 복사 생성자가 호출되는 부분은 다음과 같다.

  1. Copy() 함수의 매개변수 origin이 생성되며 한 번
  2. return값으로 전달되는 임시 객체를 생성하며 한 번

c1은 리턴되는 임시 객체의 주소를 바로 참조하게 된다.

 

NRVO (Named Return Value Optimization)은 말 그대로 Named, 함수 스코프 안에서 이름이 있는 임시 객체가 반환될 때에도 최적화를 수행하는 것이다.

즉, 위의 Copy함수가 아래와 같은 형태더라도 최적화를 수행해준다.

A Copy(A origin)
{
	A copy(origin);
	return copy;
}

NRVO는 최적화 옵션 /O1부터 동작한다고 하는데... 잘 모르겠지만 비주얼 스튜디오 기준으로 Release모드에서 적용된다.

 

 

반환값 최적화 RVO, NRVO

클래스 내에서 어떤 객체를 반환하고 싶다. 하지만 반환되는 과정의 오버헤드가 두려울 수 있다. 1 2 3 4 std::string get_name() const {     return std::string(my_name); } 일단 저 구문을 보면 이렇게..

zepeh.tistory.com

 

Rvalue 와 RVO, NRVO

C/C++를 써야만 하는 혹은 쓸 수 밖에 없는 상황들이라는 것은 대부분 성능,속도, 자원 사용의 최적화 등이지요. Visual Studio 2010에 새로이 추가된 Rvalue concept 이나 사용 예들도 정확히 이러한 상황

egloos.zum.com