C ++ std :: ref (T)와 T &의 차이점은 무엇입니까?


92

이 프로그램에 대해 몇 가지 질문이 있습니다.

#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template <typename T> void foo ( T x )
{
    auto r=ref(x);
    cout<<boolalpha;
    cout<<is_same<T&,decltype(r)>::value;
}
int main()
{
    int x=5;
    foo (x);
    return 0;
}

출력은 다음과 같습니다.

false

std::ref객체의 참조를 반환하지 않으면 무엇을하는지 알고 싶습니다 . 기본적으로 다음의 차이점은 무엇입니까?

T x;
auto r = ref(x);

T x;
T &y = x;

또한이 차이가 존재하는 이유를 알고 싶습니다. 왜 우리는 참조 가 필요 std::ref하거나 std::reference_wrapper(예 :) 때 T&필요한가?



힌트 : x = y; 두 경우 모두 수행하면 어떻게됩니까 ?
juanchopanza

2
내 중복 플래그 (마지막 댓글) 외에 : 예를 들어 stackoverflow.com/questions/31270810/…stackoverflow.com/questions/26766939/… 참조
anderas

2
@anderas 그것은 차이에 대해 주로의 유용성에 대해 아니에요
CppNITR

@CppNITR 그런 다음 귀하의 의견을 몇 초 전에 연결 한 질문을 참조하십시오. 특히 두 번째 것이 유용합니다.
anderas

답변:


91

Well ref은 객체에 reference_wrapper대한 참조를 보유하기 위해 적절한 유형의 객체를 생성합니다. 즉, 신청할 때 :

auto r = ref(x);

이것은 (즉 )에 reference_wrapper대한 직접 참조가 아닌 a를 반환합니다 . 이것은 (즉 ) 대신 유지 됩니다.xT&reference_wrapperrT&

A reference_wrapperreference복사 할 수있는 객체 를 에뮬레이션하려는 경우 매우 유용합니다 ( 복사 구성 가능복사 할당 가능 ).

C에서 + +, 당신은 참조 (예를 들어 생성되면 y객체 (말을) x한 후,) yx같은 공유 기본 주소를 . 또한 y다른 개체를 참조 할 수 없습니다. 또한 참조 배열을 만들 수 없습니다. 즉, 다음과 같은 코드에서 오류가 발생합니다.

#include <iostream>
using namespace std;

int main()
{
    int x=5, y=7, z=8;
    int& arr[] {x,y,z};    // error: declaration of 'arr' as array of references
    return 0;
}

그러나 이것은 합법적입니다.

#include <iostream>
#include <functional>  // for reference_wrapper
using namespace std;

int main()
{
    int x=5, y=7, z=8;
    reference_wrapper<int> arr[] {x,y,z};
    for (auto a: arr)
        cout << a << " ";
    return 0;
}
/* OUTPUT:
5 7 8
*/

의 문제에 대해 이야기 cout << is_same<T&,decltype(r)>::value;하면 해결책은 다음과 같습니다.

cout << is_same<T&,decltype(r.get())>::value;  // will yield true

프로그램을 보여 드리겠습니다.

#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;

int main()
{
    cout << boolalpha;
    int x=5, y=7;
    reference_wrapper<int> r=x;   // or auto r = ref(x);
    cout << is_same<int&, decltype(r.get())>::value << "\n";
    cout << (&x==&r.get()) << "\n";
    r=y;
    cout << (&y==&r.get()) << "\n";
    r.get()=70;
    cout << y;
    return 0;
}
/* Ouput:
true
true
true
70
*/

여기에서 우리는 세 가지를 알게됩니다.

  1. reference_wrapper오브젝트 (여기 r)를 생성하는데 사용될 수있는 참조의 배열 로 할 수 없었다 T&.

  2. r실제로 실제 참조처럼 작동합니다 ( r.get()=70의 값이 어떻게 변경 되었는지 참조 y).

  3. r동일하지 T&않지만 r.get()있습니다. 이 수단을 r보유하고 T&그 이름에서 알 수 있듯이 예는 것입니다 참조 주위 래퍼 T& .

이 답변이 귀하의 의심을 설명하기에 충분하기를 바랍니다.


3
1 : 아니요, a reference_wrapper다시 할당 할 수 있지만 "둘 이상의 개체에 대한 참조를 보유"할 수 없습니다. 2/3 : .get()적절한 위치에 대한 공정한 포인트 - 그러나 unsuffixed r '의 변환 이 모호하지 않게 호출 될 수있는 T&경우 와 동일하게 사용될 수 있습니다. 따라서 코드에서 여러 개를 포함하여 많은 경우 에 호출 할 필요가 없습니다 (읽기 어렵습니다. 공간 부족으로 인해). roperator.get()
underscore_d

@underscore_d reference_wrapper는 확실하지 않은 경우 참조 배열을 보유 할 수 있으며 직접 시도해 볼 수 있습니다. Plus .get()는 보유하고있는 객체의 값을 변경하고자 할 때 사용됩니다. reference_wrapper즉, r=70불법이므로 r.get()=70. 자신을보십시오 !!!!!!
Ankit Acharya 2015

1
별로. 먼저 정확한 표현을 사용합시다. "둘 이상의 객체에 대한 참조"를 포함 하는 reference_wrapper가 아니라 배열에 대한 참조를 보유 하는 reference_wrapper를 표시합니다 . 랩퍼는 하나의 참조 만 보유합니다. 둘째, 배열에 대한 기본 참조를 잘 얻을 수 있습니다. (괄호)를 잊지 않았 습니까? reference_wrapper는 네이티브 작동하기 때문에 여기서 특별 하지 않습니다 . int a[4]{1, 2, 3, 4}; int (&b)[4] = a;T&
underscore_d

1
@AnkitAcharya 예 :-) 그러나 정확하고 효과적인 결과는 제쳐두고 그 자체 는 하나의 객체만을 참조합니다. 어쨌든 일반 심판과 달리 wrapper컨테이너에 들어갈 수 있다는 것은 물론 맞습니다 . 이것은 편리하지만 사람들은 이것을 실제보다 더 진보 된 것으로 오해한다고 생각합니다. 내가 'refs'의 배열을 원한다면, 나는 보통 중개인을 건너 뛰고 vector<Item *>, 이것이 wrapper요약되는 것입니다. 그리고 anti-pointer 순수 주의자들이 나를 찾지 않기를 바랍니다. 이에 대한 설득력있는 사용 사례는 다르고 더 복잡합니다.
underscore_d

1
"reference_wrapper는 복사 할 수있는 객체의 참조를 에뮬레이션하려는 경우 매우 유용합니다." 그러나 그것은 참조의 목적을 무너 뜨리지 않습니까? 당신은 실제를 언급하고 있습니다. 그것이 바로 참조입니다. 복사 할 수있는 참조는 무의미 해 보입니다. 복사하려는 경우 처음에 참조를 원하지 않는 경우 원본 객체를 복사해야하기 때문입니다. 애초에 존재할 필요가없는 문제를 해결하는 것은 불필요한 복잡성의 층인 것 같습니다.
stu

53

std::reference_wrapper 값에 의한 전달 컨텍스트에서 참조로 객체를 전달할 수 있도록 표준 기능에 의해 인식됩니다.

예를 들어,을 ( std::bind를) 가져 와서 std::ref()값으로 전송하고 나중에 참조로 다시 압축을 풀 수 있습니다.

void print(int i) {
    std::cout << i << '\n';
}

int main() {
    int i = 10;

    auto f1 = std::bind(print, i);
    auto f2 = std::bind(print, std::ref(i));

    i = 20;

    f1();
    f2();
}

이 스 니펫은 다음을 출력합니다.

10
20

의 값 은 초기화 된 시점 i에 저장되었지만 (값으로 가져옴) by 값 을 유지 하므로 .f1f2std::reference_wrapperint&


2
@CppNITR 물론입니다! 잠시 시간을내어 작은 데모를 조립
Quentin

1
T & & REF (T)의 차이에 대해 무엇을
CppNITR

3
@CppNITR std::ref(T)std::reference_wrapper. 래핑 된 포인터에 불과하지만 라이브러리에서 "이봐, 나는 참조가 돼야 돼! 나를지나 치면 나를 하나로 되 돌려줘"라고 인식한다.
Quentin

38

참조 ( T&또는 T&&)는 C ++ 언어의 특수 요소입니다. 참조 로 객체를 조작 할 수 있으며 언어에 특별한 사용 사례가 있습니다. 예를 들어 참조를 보관할 표준 컨테이너를 만들 수 없습니다. 형식 vector<T&>이 잘못되어 컴파일 오류가 발생합니다.

반면 std::reference_wrapper에 A 는 참조를 보유 할 수있는 C ++ 객체입니다. 따라서 표준 컨테이너에서 사용할 수 있습니다.

std::refstd::reference_wrapper인수에서 를 반환하는 표준 함수입니다 . 같은 아이디어에서 const 참조로 std::cref돌아갑니다 std::reference_wrapper.

의 흥미로운 속성 중 하나 std::reference_wrapperoperator T& () const noexcept;. 즉 , 실제 객체경우에도 보유하고있는 참조로 자동 변환 될 수 있습니다. 그래서:

  • 복사 할당 가능 개체이므로 컨테이너 또는 참조가 허용되지 않는 다른 경우에 사용할 수 있습니다.
  • 덕분에 operator T& () const noexcept;자동으로 변환되므로 참조를 사용할 수있는 모든 곳에서 사용할 수 있습니다.

1
operator T& ()다른 2 개의 답변이 언급되지 않았기 때문에 주로 찬성 했습니다.
메타 블래스터
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.