JDługosz이 코멘트에 지적 @ 허브는 (? 이상) 또 다른 조언을 제공으로 이야기를 여기에서 약 참조 : https://youtu.be/xnqTKD8uD64?t=54m50s .
그의 조언 f
은 싱크 인수에서 구문을 이동한다고 가정 할 때 소위 싱크 인수를 취하는 함수에 값 매개 변수를 사용하는 것으로 요약됩니다 .
이 일반적인 접근 방식 f
은 lvalue 및 rvalue 인수에 각각 최적화 된 구현과 비교하여 lvalue 및 rvalue 인수 모두에 대해 이동 생성자의 오버 헤드 만 추가합니다 . 이것이 왜 그런지 보려면 f
, T
복사 및 이동 구성 가능한 유형 이있는 value 매개 변수를 사용 한다고 가정하십시오 .
void f(T x) {
T y{std::move(x)};
}
호출 f
복사 생성자가 발생합니다 좌변 인수는 구조에 호출되고 x
, 및 이동 생성자는 구성하기 위해 호출되는 y
. 반면에 f
rvalue 인수를 호출 하면 이동 생성자가 구성하기 위해 호출 x
되고 다른 이동 생성자가 호출되어 생성됩니다.y
됩니다.
일반적으로 f
lvalue 인수 에 대한 최적의 구현은 다음과 같습니다.
void f(const T& x) {
T y{x};
}
이 경우 하나의 복사 생성자 만 생성하여 호출됩니다 y
. f
rvalue 인수 에 대한 최적의 구현은 일반적으로 다음과 같습니다.
void f(T&& x) {
T y{std::move(x)};
}
이 경우 하나의 이동 생성자 만 호출되어 생성됩니다. y
.
따라서 합리적인 타협은 가치 매개 변수를 취하고 최적의 구현과 관련하여 lvalue 또는 rvalue 인수를 하나 더 이동 생성자가 호출하는 것입니다.
@ JDługosz가 주석에서 지적했듯이 값을 전달하면 싱크 인수에서 일부 객체를 구성하는 함수에만 적합합니다. f
인수를 복사 하는 함수가있는 경우 값별 접근 방식은 일반적인 통과 기준 접근 방식보다 더 많은 오버 헤드를 갖습니다. f
매개 변수의 사본을 보유하는 함수 에 대한 값별 접근 방식 은 다음과 같습니다.
void f(T x) {
T y{...};
...
y = std::move(x);
}
이 경우, lvalue 인수에 대한 복사 구성 및 이동 지정과 rvalue 인수에 대한 이동 구성 및 이동 지정이 있습니다. lvalue 인수에 가장 적합한 경우는 다음과 같습니다.
void f(const T& x) {
T y{...};
...
y = x;
}
이것은 할당으로 만 귀결되는데, 이는 복사 생성자보다 값이 저렴하고 값으로 전달하는 방법에 필요한 이동 할당보다 훨씬 저렴합니다. 할당이 기존의 할당 된 메모리를 재사용 할 수 있기 때문입니다.y
방지 할 수있는 반면, 복사 생성자는 일반적으로 메모리를 할당하기 때문입니다.
rvalue 인수의 f
경우 사본을 보유 하기위한 가장 최적의 구현 은 다음 형식을 갖습니다.
void f(T&& x) {
T y{...};
...
y = std::move(x);
}
따라서이 경우 이동 할당 만 가능합니다. f
const 값 을 갖는 버전으로 rvalue를 전달하면 이동 할당 대신 할당 비용 만 발생합니다. 상대적으로 말하자면f
이 경우 일반적인 구현으로 const 참조 취하는 이 바람직합니다.
따라서 일반적으로 가장 최적의 구현을 위해서는 대화에서 볼 수 있듯이 오버로드하거나 일종의 완벽한 전달을 수행해야합니다. 단점은 f
인수의 값 범주에서 과부하를 선택하는 경우 매개 변수의 수에 따라 필요한 과부하 수의 조합 폭발입니다 . 퍼펙트 포워딩은 f
템플릿 기능이되는 단점이 있어, 가상으로 만드는 것을 막고, 100 % 올바른 결과를 얻으려면 훨씬 더 복잡한 코드를 생성합니다.