pass by value가 효율적인 경우

김대익·2022년 2월 25일
post-thumbnail
#include <string>
using namespace std;

string getString() {
	string s = "nocodeabc";
    return s;
}

int main() {
	string a = getString();
    return 0;
}


이 코드를 memory에서 보면 main함수 stack frame이 생성되면서
stack에 변수 a에 대해 생성되는데 a는 아직 아무 것도 가리키고 있지 않다.
이후 a = getString();에서 getString 함수가 실행되면서 getString에 대한 stack frame이 생성된다.
stack frame에 s가 생성되고 이는 heap안에 저장한 "nocodeabc"을 가리킨다.
이후 a = getString()을 위해 "nocodeabc"이 heap에 복사되고 이 주소를 stack에 있는 a가 가리키게 된다.
그리고 getString의 stack frame이 해제된다.


이 한번의 복사가 일어나는 것을 막기 위해
return std::move(s)로 바꾸려고 시도하는 경우가 있는데,
실제로는 RVO가 개입되면서 작동되지 않는다.

실제 동작하는 방식을 보면
main함수가 실행되면서 stack frame이 생성되면서 stack에 a라는 string object가 생긴다.
그 후 getString함수가 실행되면서 stack frame이 만들어지면서 local variable, args, return value address를 갖는데, 여기서 return value address는 a를 가리킨다.
컴파일러는 return value address가 a를 가리키는 것을 알고있기에
함수 안에서 heap공간에 "nocodeabc"를 만들고 return value address가 가리키는 a가 heap공간의 "nocodeabc"를 가리키게 만들고 getString함수의 stack frame은 해제가 된다.
따라서 RVO가 개입되면서 local string object인 s는 처음부터 존재하지 않게 된다.
따라서 소유권의 이동(move)조차 없었고
그리고 "nocodeabc"도 copy되지 않아 0copy를 이뤄냈다.
따라서 getString()에서 returnByValue인 return s를 하면 RVO가 개입되면서 가장 효율적으로 a에 "nocodeabc"를 할당시킨다.


보통 코딩시 RVO가 거의 모든 경우 개입이 되는데
개입이 안되는 경우도 있다.

이렇게 if문으로 될 경우 getString함수의 인수 a를 바로 main함수의 string a에게 넘겨줄지,
getString함수의 "nocodeprogram"을 넘겨줄지 모르기 때문에 RVO가 개입되지 않는다.
하지만 main함수의 string a = getString()에서 move constructor가 동작되기 때문에 0copy는 유지된다.

0개의 댓글