왜 필요가 std::reference_wrapper
있습니까? 어디에서 사용해야합니까? 간단한 포인터와 어떻게 다릅니 까? 성능이 간단한 포인터와 어떻게 비교됩니까?
.
은 제안한 방식으로 작동하지 않습니다 (어떤 시점에서 오퍼레이터 도트 제안이 채택되고 통합되지 않는 한 :))
get()
멤버 함수 또는 기본 형식으로의 암시 적 변환과 함께 사용됩니다 .
왜 필요가 std::reference_wrapper
있습니까? 어디에서 사용해야합니까? 간단한 포인터와 어떻게 다릅니 까? 성능이 간단한 포인터와 어떻게 비교됩니까?
.
은 제안한 방식으로 작동하지 않습니다 (어떤 시점에서 오퍼레이터 도트 제안이 채택되고 통합되지 않는 한 :))
get()
멤버 함수 또는 기본 형식으로의 암시 적 변환과 함께 사용됩니다 .
답변:
std::reference_wrapper
템플릿과 함께 사용하면 유용합니다. 객체에 대한 포인터를 저장하여 객체를 래핑하고 일반적인 의미를 모방하면서 재 할당 및 복사를 허용합니다. 또한 특정 라이브러리 템플릿에 개체 대신 참조를 저장하도록 지시합니다.
펑터를 복사하는 STL의 알고리즘을 고려하십시오. 펑터 자체 대신 펑터를 참조하는 참조 래퍼를 전달하면 해당 복사를 방지 할 수 있습니다.
unsigned arr[10];
std::mt19937 myEngine;
std::generate_n( arr, 10, std::ref(myEngine) ); // Modifies myEngine's state
이것은 작동하기 때문에 ...
… reference_wrapper
s 오버로드operator()
이므로 참조하는 함수 객체처럼 호출 할 수 있습니다.
std::ref(myEngine)() // Valid expression, modifies myEngines state
… (비) 일반적인 참조와 달리 복사 (및 할당) reference_wrappers
는 pointee를 할당합니다.
int i, j;
auto r = std::ref(i); // r refers to i
r = std::ref(j); // Okay; r refers to j
r = std::cref(j); // Error: Cannot bind reference_wrapper<int> to <const int>
참조 래퍼를 복사하는 것은 포인터를 복사하는 것과 거의 동일합니다. 사용에 내재 된 모든 함수 호출 (예 :에 대한 호출 operator()
)은 한 줄짜리이므로 인라인되어야합니다.
reference_wrapper
들로 만들어집니다 std::ref
및std::cref
:
int i;
auto r = std::ref(i); // r is of type std::reference_wrapper<int>
auto r2 = std::cref(i); // r is of type std::reference_wrapper<const int>
template 인자는 참조 된 객체의 유형과 cv-qualification을 지정합니다. r2
를 참조하고에 const int
대한 참조 만 생성합니다 const int
. const
펑터가있는 참조 래퍼에 대한 호출은 const
멤버 함수 만 호출 합니다 operator()
.
Rvalue 이니셜 라이저는 허용하면 득보다 해를 끼칠 수 있으므로 허용되지 않습니다. rvalue는 어쨌든 이동 될 것이기 때문에 (그리고 부분적으로 피할 수 있는 보장 된 복사 제거 와 함께 ) 의미 체계를 개선하지 않습니다. 참조 래퍼가 pointee의 수명을 연장하지 않기 때문에 매달린 포인터를 도입 할 수 있습니다.
앞에서 언급했듯이 해당 인수를 a를 통해 전달하여 make_tuple
결과 tuple
에 참조를 저장 하도록 지시 할 수 있습니다 reference_wrapper
.
int i;
auto t1 = std::make_tuple(i); // Copies i. Type of t1 is tuple<int>
auto t2 = std::make_tuple(std::ref(i)); // Saves a reference to i.
// Type of t2 is tuple<int&>
forward_as_tuple
다음 과 약간 다릅니다 . 여기서, rvalue는 인수로 사용할 수 없습니다.
std::bind
동일한 동작을 보여줍니다. 인수를 복사하지 않고 reference_wrapper
. 해당 인수 (또는 functor!)를 복사 할 필요는 bind
없지만 -functor가 사용되는 동안 범위에 남아있는 경우 유용합니다 .
추가적인 수준의 구문 적 간접 지정은 없습니다. 포인터가 참조하는 객체에 대한 lvalue를 얻으려면 포인터를 역 참조해야합니다. reference_wrapper
에는 암시 적 변환 연산자 가 있으며 래핑 된 객체처럼 호출 될 수 있습니다.
int i;
int& ref = std::ref(i); // Okay
reference_wrapper
s는 포인터와 달리 null 상태가 아닙니다. 그것들은 참조 또는 다른reference_wrapper
것으로 초기화되어야 합니다 .
std::reference_wrapper<int> r; // Invalid
유사점은 얕은 복사 의미 체계입니다. 포인터와 reference_wrapper
s를 다시 할당 할 수 있습니다.
std::make_tuple(std::ref(i));
뛰어난 std::make_tuple(&i);
어떤 방법으로?
i
는 참조가 아니라에 대한 포인터를 저장 합니다.
최소한 두 가지 동기 부여 목적이 있습니다 std::reference_wrapper<T>
.
함수 템플릿에 값 매개 변수로 전달 된 객체에 참조 의미를 부여하는 것입니다. 예를 들어, std::for_each()
값으로 함수 객체 매개 변수 를 사용 하는 전달하려는 큰 함수 객체가있을 수 있습니다 . 개체 복사를 방지하려면 다음을 사용할 수 있습니다.
std::for_each(begin, end, std::ref(fun));
표현식 std::reference_wrapper<T>
에 대한 인수를 전달 하는 std::bind()
것은 값이 아닌 참조로 인수를 바인딩하는 데 매우 일반적입니다.
해당 튜플 요소 std::reference_wrapper<T>
와 함께 사용하면 std::make_tuple()
a T&
가 아닌 a가됩니다 T
.
T object;
f(std::make_tuple(1, std::ref(object)));
fun
함수가 아닌 함수 객체 (즉, 함수 호출 연산자가있는 클래스의 객체) 일 가능성 이 높습니다 fun
. 실제 함수 인 std::ref(fun)
경우 목적이없고 코드를 잠재적으로 느리게 만듭니다.
자체 문서화 코드의 또 다른 차이점은을 사용하면 reference_wrapper
본질적으로 객체의 소유권을 거부한다는 것입니다. 반대로, a unique_ptr
는 소유권을 주장하지만, 베어 포인터는 소유 할 수도 있고 아닐 수도 있습니다 (많은 관련 코드를 살펴 보지 않고는 알 수 없습니다).
vector<int*> a; // the int values might or might not be owned
vector<unique_ptr<int>> b; // the int values are definitely owned
vector<reference_wrapper<int>> c; // the int values are definitely not owned
reference_wrapper
비 소유라는 것이 분명하기 때문일뿐만 아니라 (비 소유 nullptr
없이) 될 수 없기 때문에 사용자가 통과 할 수 없다는 것을 알고 ( 비 소유 없이) 통과 nullptr
할 필요가 없다는 것을 알기 때문에 원시 포인터보다 우수 합니다. 그것을 확인하십시오.
컨테이너에서 사용할 수 있도록 참조를 둘러싼 편리한 래퍼로 생각할 수 있습니다.
std::vector<std::reference_wrapper<T>> vec; // OK - does what you want
std::vector<T&> vec2; // Nope! Will not compile
그것은 기본적으로 A의 CopyAssignable
버전 T&
. 참조를 원할 때마다 할당 가능해야 std::reference_wrapper<T>
하거나 도우미 기능을 사용해야 합니다 std::ref()
. 또는 포인터를 사용하십시오.
기타 단점 : sizeof
:
sizeof(std::reference_wrapper<T>) == sizeof(T*) // so 8 on a 64-bit box
sizeof(T&) == sizeof(T) // so, e.g., sizeof(vector<int>&) == 24
그리고 비교 :
int i = 42;
assert(std::ref(i) == std::ref(i)); // ok
std::string s = "hello";
assert(std::ref(s) == std::ref(s)); // compile error
reference_wrapper
코드 를 인라인하여 포인터 나 참조를 사용하는 코드와 동일하게 만들 것으로 예상합니다 .
std::reference_wrapper
개체가 null이 아님을 보장합니다. 반원을 생각해보십시오 std::vector<T *>
. 이 객체가 nullptr
벡터에 a 를 저장할 수 있는지 확인하려면 모든 클래스 코드를 검사해야하는 반면에서는 std::reference_wrapper<T>
유효한 객체가 보장됩니다.
.
대신 사용하는 포인터 입니다->