[복사 생략] 복사 생략
1. 복사 생략(Copy Elision)
이동에 대한 개념을 다루기 전에 컴파일러가 불필요한 복사와 이동 연산을 최적화하기 위해 사용하는 기술을 다룹니다.
해당 내용은 VC의 기준이며, C++ 17 이상, 최적화 컴파일 옵션을 적용한 Release 버전 기준입니다.
1-1 RVO(Return Value Optimization)
C++17 이후에 반드시 적용되는 RVO는, 함수가 지역 변수(객체)를 반환할 때 임시 객체의 생성 자체를 피하고
직접 반환 값이 저장될 위치에 객체를 생성하는 최적화 기법입니다.
함수의 리턴이 아닌 이름 없는 임시 객체의 경우에도 이것이 적용되었습니다.
#include <iostream>
using namespace std;
class A {
int data_;
public:
A(int data) : data_(data) { std::cout << "일반 생성자 호출!" << std::endl; }
A(const A& a) : data_(a.data_) {
std::cout << "복사 생성자 호출!" << std::endl;
}
};
class Test
{
string s_;
public:
Test(string s) : s_(s) { cout << "일반 생성자 호출 !" << endl; }
Test(const Test& other) : s_(other.s_) { cout << "복사 생성자 호출 !" << endl; }
};
int main() {
A a1(5);
A a2(a1);
A a3(A(2));
cout << "---------------------------------" << endl;
Test b1("power");
Test b2(b1);
Test b3 = Test("test");
}
a3, b3의 경우 복사 생성자가 호출될 것 같지만, a3, b3 자체에서 일반 생성자를 통해 객체를 생성하였습니다.
1-2 NRVO(Named Return Value Optimization)
함수가 이름 있는 임시 객체의 생성을 반환할 때에도, 임시 객체의 생성을 피하고 직접 반환 값이 저장될 위치에
객체를 생성하는 최적화 기법입니다.
class Test
{
string s_;
public:
Test(string s) : s_(s) { cout << "일반 생성자 호출 !" << endl; }
Test(const Test& other) : s_(other.s_) { cout << "복사 생성자 호출 !" << endl; }
void Getter() { cout << s_ << endl; }
};
Test Return_Test()
{
Test t1("power");
return t1;
}
int main() {
Test mainTest = Return_Test();
mainTest.Getter();
}
해당 경우에는 Return_Test() 함수 내부에서
1. 임시 객체를 생성하고
2. mainTest에서 복사 생성자를 통해 객체를 생성할 것으로 기대됩니다.
그러나 mainTest 에서 일반 생성자를 최초 한 번만 호출하였습니다.
함수 내부에서 "power" 라는 생성자 인자를 통해 멤버 변수를 초기화한 것도 잘 적용이 되었습니다.
Debug, Release 모두 동일
'개념과 활용 > C++' 카테고리의 다른 글
[C++] new [], delete [] (0) | 2024.06.18 |
---|---|
[연산자 오버로딩] 연산자 오버로딩과 반환 값 (0) | 2024.06.14 |
[상속] 접근 지정자와 상속 접근 지정자 (0) | 2024.06.13 |
[복사 생략] 이동 생성자와 이동 대입 연산자 (0) | 2024.06.11 |
[다형성] 추상 클래스와 가상 함수 테이블 (0) | 2024.06.08 |
댓글