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로 바뀌어서 내가 고치진 못할듯..
이건몰랐네
개추드립니다
몰랐네
예전에 Effient cpp 읽었을때 나왔던 내용이네. 임시객체 만들면 느려질수 있대.
그래서 c = a + b보다 c = a; c+=b보다 빠르다고도 하더라.
앞이 빠름 뒤가 빠름?
아 잘못 씀. 뒤가 빠르대.
이건 오히려 글 내용에 따라 전자의 a + b가 prvalue expression이면 copy elision이 일어나니 후자의 copy/move + inplace operation이랑 속도 차이가 없어지는거 같은데..
중요한거 한가지 빼먹었는데 c가 미리 정의되어있을때임. 바로 =로 덮어쓸 권한이 없어서 임시객체가 필요하다네.
그럼 막 행렬 더하고 그럴땐 a + b에선 새 object 만드느라 allocate 해야하니 행렬이 작아서 allocation이 copy보다 느릴땐 후자가 더 빠를수도 있겠네. 근데 만약 크기가 존나 커서 copy가 더 느릴땐 전자가 더 빠를수도 있을거 같음. 좀 애매한건 둘째 치더라도 prvalue랑은 상관이 있다 보기 힘든거 같음
물론 후자를 c = std::move(a); c += b;로 고치면 웬만하면 더 빠를 거 같음
무브하면 확실히 빠를듯
(모던씨피피콘) - dc App
foo() 는 보통 무슨 의미야?
그냥 예시 코드 적을때 자주 쓰는 이름임 (foo, bar, baz, …) 별 의미는 없을걸