정진하는중

[복사 생략] 복사 생략

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 자체에서 일반 생성자를 통해 객체를 생성하였습니다.

 

Debug, Release 모두 동일

 

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 모두 동일

 

 

 

 

 


댓글