STL과 RValue Reference
앞선 글에서 C++0x의 STL에는 RValue Reference가 적용되었다고 말했습니다.
이 덕분에 기존의 코드를 수정하지 않고 C++0x의 컴파일러로 빌드만 해도 프로그램의 성능이 좋아집니다.
RValue Reference가 적용된 C++0x의 STL vector
VC++ 10의 vector쪽 소스 코드를 보면 이전의 vector에는 없던 코드가 있습니다.
< Code 1. STL의 vector의 소스 중 일부 >
……………………
#if _HAS_RVALUE_REFERENCES
vector(_Myt&& _Right)
: _Mybase(_Right._Alval)
{ // construct by moving _Right
_Assign_rv(_STD forward<_Myt>(_Right));
}
………
<Code 1>의 내용을 보면 바로 아시겠죠? 네 Move 생성자가 정의 되어 있습니다.
< Code 2. >
vector<int> foo()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
return v;
}
int main()
{
vector<int> v1 = foo();
cout << v1[0] << endl;
return 0;
}
<Code 2>를 VC++9(visual Studio 2008)와 VC++ 10(Visual Studio 2010 CTP)에서 컴파일 해서 실행하면 vector의 생성자에서 서로 다른 부분을 호출하는 것을 볼 수 있습니다.
VC++ 9에서 <Code 2> 디버깅
VC++ 9에서 디버깅을 해보면 다음의 위치에서 브레이크 포인터가 걸립니다.
위 코드를 보면 복사 생성자에서 받은 vector의 크기를 비교하여 현재 공간이 인자로 받은 vector보다 작으면 재할당을 하고, vector에 있는 모든 요소를 복사합니다.
VC++ 10에서 <Code 2> 디버깅
보시는 바와 같이 VC++ 10에서는 Move 생성자가 호출됩니다. 그리고 요소를 복사하지 않고 메모리 상의 이동을 합니다.
크기가 작은 vector라면 성능상의 차이는 별 의미가 없겠지만 크기가 큰 vector라면 무시하지 못할 차이가 납니다.
또한 vector에 할당된 공간을 다 사용한 상태에서 새로운 요소를 삽입하면( vector.push_bask() ) 기존에는 새로운 공간을 할당 후 저장하고 있던 모든 요소를 복사를 하지만 C++0x에서는 Move Semantics에 의해 메모리 상의 이동을 합니다.
STL의 string
< Code 3. string 결합>
string msg1(“Error”);
string msg2(“- Network”);
string msg3(“: Accept”);
string Msg = msg1 + “ “ + msg2 + “ “ + msg3;
<Code 3>에 만약 RValue Reference가 적용되지 않았다면 operator+()가 호출될 때마다 임시 문자열이 생성되어 동정 메모리 할당과 복사가 일어나지만 RValue Reference을 적용하면 불 필요한 동적 메모리 할당과 복사 처리를 제거할 수 있습니다.
std::move()를 사용할 때 주의할 점
int main()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(12);
vector<int> v2 = std::move(v1);
cout << v1.size() << endl;
cout << v2.size() << endl;
return 0;
}
< 결과 >
<Code 4>에서 v1을 v2에서 Move 생성자를 사용하기 위해서 std::move()를 사용했습니다.
std::move는 메모리 이동을 한다고 했습니다. 그래서
vector<int> v2 = std::move(v1);
이 후에는 v1의 크기는 0이 됩니다.
이것으로 RValue Reference에서의 Move Semantics에 대한 이야기는 일단락합니다.
제가 너무 복잡하지 않게 설명하기 위해 세세한 부분에 대한 것은 설명하지 않았으니 좀 더 정확하게 알고 싶은 분들은
http://blogs.msdn.com/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx 와 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html
의 글을 꼭 보시기 바랍니다.
다음에는 Perfect Forwarding에 대하여 이야기로 우측참조에 대한 글을 끝맺겠습니다.
'C++0x' 카테고리의 다른 글
| [VC++] 9. Lambda ( 람다 ) - 첫 번째 (4) | 2009/06/02 |
|---|---|
| [VC++] 8. 우측 값 참조( RValue Reference ) – 다섯 번째 (3) | 2009/05/26 |
| [VC++] 7. 우측 값 참조( RValue Reference ) - 네 번째 (3) | 2009/05/20 |
| [VC++] 6. 우측 값 참조( RValue Reference ) - 세 번째 (0) | 2009/05/09 |
| [VC++] 5. 우측 값 참조( RValue Reference ) – 두 번째 (2) | 2009/05/06 |
| [VC++] 4. 우측 값 참조( RValue Reference ) - 첫 번째 (2) | 2009/05/04 |




댓글을 달아 주세요
잘보았습니다. ^^
잘 봤습니다.
그런데 메모리상의 이동이라고 표현하시는데...
실제론 그냥 개체 포인터의 복사 및 소스포인터 nullify가 전부 아닌가요?
메모리의 이동이라고 표현하니 웬지 물리적 페이지가 프로세스 내의 가상주소공간에서 이동하는 것처럼 들려서 좀 헷갈리네요.
그리고 code 3 에선 operator+() 호출시에 임시개체가 생성되고 memcpy, 심지어 문자열이 길면 malloc 도 호출됩니다.
단지 2번째 operator+() 호출부터는 각 임시개체간에 데이터 복사 대신 포인터 대입 및 소스포인터 nullify 가 일어날 뿐이죠.
물론 그래봤자 2번째 피연산자 역시 길이가 길다면 임시개체에 대하여 malloc 및 memcpy 호출이 발생합니다.
그리고 연산이 다 끝난 후에도 임시개체의 포인터가 Msg 에 직접 대입된 후 임시개체의 버퍼 포인터가 nullify 될 뿐이구요.
물론 malloc 와 memcpy 가 2번 호출될 것이 1번으로 줄긴 했지만서두...
아무튼 Move Semantics 이란게 뭔가 했더니...
난 또 무슨 page remapping 쯤 되는줄 알았는데...
머리가 간지럽다고 해서 손바닥을 긁어 머리에 갖다대는 수준의 병맛스런 개념이었군요.
에효... 언제나 c++ 이 제정신으로 돌아오려는지...
불필요한 작업을 없애는 정도네요...