본문 바로가기

프로그래밍/C++

C++11 이동생성자 (Move Constructor)



Rvalue Reference가 추가되면서 같이 추가된 이동생성자에 대한 설명이다.



이동생성자를 사용하는 궁극적인 목적은 바로 성능향상인데,


아래의 예제를  통해 설명함.



#include <vector>

#include <string>

#include <iostream>


using namespace std;


struct Person

{

string name;

int year;


Person(string p_name, int p_year)

: name(move(p_name)), year(p_year)

{

cout << "I am being constructed.\n";

}


Person(const Person& other)

: name(move(other.name)), year(other.year)

{

cout << "I am being copied.\n";

}


Person(Person&& other)

: name(move(other.name)), year(other.year)

{

cout << "I am being moved.\n";

}


~Person()

{

cout << "I am being destructed.\n";

}


Person& operator=(const Person& other) = default;

};

이름과 출생년도를 멤버로 가지고 있는 Person 이라는 구조체를 하나 정의하였는데,


기본생성자외에 생성자가 2개 더 있다.


하나는 복사생성자이고 그 다음 생성자가 바로 이동생성자이다.


보시다시피 이동생성자의 파라미터는 오른쪽값 참조이다.


오른쪽값 참조에 대한 설명은 여기에서 참조 - http://honestgame.tistory.com/83


이건 문법이 이렇게 되어 있기 때문에 이렇게 따라줘야 한다.


정의는 복사생성자와 다를바 없다.



int main()

{

  vector<Person> generalList;


generalList.push_back(Person("Yi Sun-shin", 1545));


for (Person const& Person : generalList)

{

cout << "Name: " << Person.name 

    <<" Birth:<<Person.year <<endl;

}

}


다음은 main 부분인데,


Person 컨테이너를 하나 만들고, push_back 하였는데


Person객체를 생성하면서 집어넣었다.


그렇다면 어떻게 될까?


1. 파라미터 자체가 임시 객체이므로 일단 기본 생성자가 호출된다.


2. 임시객체가 컨테이너로 옮겨지면서 이동생성자가 호출된다.


3. 임시객체가 파괴되면서 소멸자 호출


4. Person 객체 정보 출력


5. 컨테이너에 있던 Person 객체가 소멸되면서 소멸자 호출



I am being constructed.


I am being moved.


I am being destructed.


Name: Yi Sun-shin Birth: 1545


I am being destructed.


그런데, 만약 이동생성자를 정의하지 않았다면 어떻게 될까?



I am being constructed.


I am being copied.


I am being destructed.


Name: Yi Sun-shin Birth: 1545


I am being destructed.


이동생성자가 호출되지 않고, 복사생성자가 호출된다!!


그렇다면 왜 복사생성자를 호출하지 않고, 이동생성자를 호출하는 이유는 무엇일까?


서두에도 이야기하였지만, 바로 이동생성자가 월등히 빠르기 때문이다.


http://wonderfuldream.tistory.com/347




다음에 생각해볼 문제는 push_back을 할 경우,


임시 객체가 생성이 되면서 불필요한 생성자와 소멸자가 호출된다는 것이다.


그럴경우, emplace_back()을 사용하면 된다.( C++11이 도입된 컴파일러에서 적용 )


http://www.cplusplus.com/reference/vector/vector/emplace_back/


바로 컨테이너 내부에서 바로 객체가 생성이 된다.


int main()

{

vector<Person> generalList;


generalList.emplace_back("Yi Sun-shin", 1545);


for (Person const& Person : generalList)

{

cout << "Name: " << Person.name 

    <<" Birth:<<Person.year <<endl;

}

}



I am being constructed.


Name: Yi Sun-shin Birth: 1545


I am being destructed.


깔끔하게 생성자 한번만 호출된다.



그렇다면 여기서 질문이 하나 생기게 되는데,


항상 insert, push_back 보다 emplace 나 emplace_back 이 낫다고 볼 수 있는가?


스캇메이어 아저씨의 의견에 따르면 


이론적으로 성능은 후자가 낫다고 한다. - http://honestgame.tistory.com/71


전자를 사용해야 할 경우도 있는데,


리소스 해지 문제나 다른 문제가 엮일 경우가 있을때이다.


성능을 고려한다면 emplace을 고려하라고 권장하고 싶다.


끝.