2018-02-09

[C++] copy elision - 복사 생성자는 생략될 수 있다

 위의 코드를 실행하면 무엇이 출력될까? A기본 생성자로 인스턴스를 생성하고 이것을 a에 복사하는 복사 할당이 한 번 불렸으므로 "0 1"이라고 생각할 수 있다.
 하지만 위의 코드에서는 복사 할당이 불리지 않는다. 할당자는 이미 초기화돼 있는 값에 새 값을 할당하는 연산자이기 때문이다. 따라서 위의 코드는 사실 A a(A());와 같은 의미이고 복사 생성자가 불리는 코드다. 이를 복사 할당자를 불리게 하고 싶으면 아래와 같이 a가 초기화된 상태에서 값을 대입해야 한다.  그렇다면 처음 코드는 정말로 "1 0"을 출력할까?

 사실 이건 C++ 버전에 따라 다르다. 우선 C++ 14 까지는 "1 0" 혹은 "0 0"이 출력된다. 이는 C++ 14까지는 어떤 레퍼런스에도 바인드 되지 않는 temporary object를 인자로 받는 이동 생성자와 복사 생성자를 생략하는 copy elision을 허용하기 때문이다.
 보통 최적화는 실행 결과를 변경시키지 않기 위해서, side-effect가 없는 경우에 대해서만 허용하는 것이 보통이다. 위의 코드는 전역 변수를 수정하기 때문에 side-effect가 있는 함수고, 따라서 최적화되지 않을 거로 생각하기 쉽다. 하지만 copy elision은 복사 생성자와 소멸자가 side-effect가 있는 함수라도 허용된다. 즉, 어떻게 최적화했는지에 따라 코드의 실행 결과가 달라질 수 있다는 것이다. 따라서 위의 코드는 copy elision이 됐다면 "0 0"이 출력될 것이고, copy elision이 되지 않았다면 "1 0"이 출력될 것이다.

 C++ 17에서 위의 코드는 반드시 "0 0"를 출력한다. prvalue를 인자로 받는 복사/이동 생성자를 없애는 copy elision을 반드시 수행하도록 스펙이 수정됐기 때문이다.

댓글 없음:

댓글 쓰기