https://gall.dcinside.com/mgallery/board/view/?id=github&no=28510

이 글을 보고 생각나서 c++20 기준으로 적어봄


1. 임시 변수 초기화하고 리턴

std::vector<int> foo() {

std::vector<int> ret = { 1, 2, 3 };

return ret;

}


이 경우에서는 NRVO가 가능하지만 강제되지는 않는다.

따라서, copy/move constructor이 observable side effect를 갖고 있더라도 return object에 다이렉트로 ret가 construct되도록 최적화 하는 것이 가능하다.

하지만 이 경우에서도 표준에서 보장하는 최적화가 하나 있다. (Implicit move)

ret가 lvalue라 해서 copy constructor부터 찾는게 아니라, ret를 rvalue처럼 본 후에 overload resolution을 시행하고 실패시 ret을 평소처럼 lvalue로 본 후에 다시 overload resolution을 시행한다,

이 경우에선 첫 overload resolution에서 std::vector의 move constructor이 선택되게 되고, 따라서 copy대신 move가 일어난다.

이 Implicit move 메커니즘이 좀 이것저것 문제가 있어서 개선하자는 proposal도 있으니 궁금하면 한번 읽어봐 (고장난 링크)


2. prvalue 리턴

std::vector<int> foo() {

return { 1, 2, 3 };

}

이 함수는 std::vector<int>의 prvalue를 return하는데, 경우에는 RVO를 시행하도록 표준이 강제한다.

prvalue는 type을 construct를 하기 위한 방법을 담고 있고, 이를 이용해 어떤 변수를 initialize할때 비로소 거기다 construct 하는 존재라고 보면 된다.

따라서, auto hi = foo();를 하면 hi라는 변수를 initialize할때 그제서 std::vector<int> { 1, 2, 3 }으로 hi에다 다이렉트로 construct가 일어난다.

이 경우에는 위와는 다르게 아예 overload resolution이 시행되지 않기에, 설령 std::vector<int>가 이 경우에서 사용가능한 constructor이 없어도 잘만 컴파일 된다.

이를 이용해 copy나 move를 할 수 없는 타입들을 리턴하는 함수를 작성하는 듯, 이것저것 할 수 있다.


예시)

struct StrangeStruct {

StrangeStruct() = default;

StrangeStruct(const StrangeStruct&) = delete;

StrangeStruct(StrangeStruct&&) = delete;

};


StrangeStruct i_return_prvalue() {

return StrangeStruct();

}


int main() {

auto hi = StrangeStruct(StrangeStruct(i_return_prvalue()));

}


잘 컴파일 된다. (Godbolt)


ps) 고장난 링크가 누르면 내 폰에선 안 열리던데 https 대신 http로 수정해서 열면 열린다. 뭔 짓을 해도 글에 링크 적으면 https로 바뀌어서 내가 고치진 못할듯..