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; दोनों मामलों में करते हैं तो क्या होगा ?
जुआनकोपंजा

2
मेरे डुप्लिकेट फ़्लैग के अलावा (अंतिम टिप्पणी): उदाहरण के लिए देखें stackoverflow.com/questions/31270810/… और stackoverflow.com/questions/26766939/…
anderas

2
@anderas यह उपयोगिता के बारे में नहीं है, यह मुख्य रूप से अंतर के बारे में है
CppNITR

@CppNITR फिर उन प्रश्नों को देखें जिन्हें मैंने आपकी टिप्पणी से कुछ सेकंड पहले लिंक किया था। विशेष रूप से दूसरा एक उपयोगी है।
औरसीस

जवाबों:


91

अच्छी तरह से refएक वस्तु का reference_wrapperसंदर्भ रखने के लिए उपयुक्त प्रकार की एक वस्तु का निर्माण करता है । जिसका अर्थ है जब आप आवेदन करें:

auto r = ref(x);

यह (यानी ) के reference_wrapperलिए एक सीधा संदर्भ देता है और नहीं । यह (यानी ) इसके बजाय रखती है ।xT&reference_wrapperrT&

एक reference_wrapperबहुत उपयोगी है जब आप एक अनुकरण करने के लिए चाहते हैं referenceएक वस्तु जो कॉपी किया जा सकता की (यह दोनों है कॉपी-constructible और कॉपी-आबंटित )।

C ++ में, एक बार आप एक संदर्भ (जैसे बनाने के yलिए एक वस्तु (कहने के लिए) x), तो yऔर xएक ही साझा आधार पते । इसके अलावा, 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: नहीं, फिरreference_wrapper से असाइन किया जा सकता है , लेकिन यह "एक से अधिक वस्तुओं के संदर्भ नहीं रख सकता है"। 2/3: उचित बिंदु के बारे में जहां .get()उचित है - लेकिन अनुपयोगी का r उपयोग उन T&मामलों में भी किया जा सकता है, जहां rरूपांतरण operatorको स्पष्ट रूप से लागू किया जा सकता है - इसलिए .get()आपके कोड में कई (जिनमें पढ़ना मुश्किल है) सहित कई मामलों में कॉल करने की आवश्यकता नहीं है। रिक्त स्थान की कमी के कारण)।
अंडरस्कोर_ड

@underscore_d reference_wrapperसंदर्भों की एक सरणी को पकड़ सकता है यदि आप सुनिश्चित नहीं हैं तो आप इसे स्वयं आज़मा सकते हैं। प्लस .get()का उपयोग तब किया जाता है जब आप उस वस्तु के मूल्य को बदलना चाहते हैं जो reference_wrapperकि होल्डिंग है अर्थात r=70अवैध है इसलिए आपको उपयोग करना होगा r.get()=70। अपने आप कोशिश करो !!!!!!
अंकित आचार्य

1
ज़रुरी नहीं। पहले, चलो सटीक शब्द का उपयोग करें। आप एक रेफ़र_वॉपर को एक एरे के सन्दर्भ में रखते हुए दिखा रहे हैं - न कि एक रेफरेंस_वॉपर जिसमें खुद "एक से अधिक ऑब्जेक्ट्स के लिए रेफ़रेंस" हो । रैपर केवल एक संदर्भ रखता है। दूसरे, मैं एक सरणी के लिए एक मूल संदर्भ प्राप्त कर सकता हूं बस ठीक है - क्या आप सुनिश्चित हैं कि आप (कोष्ठक) को भूल नहीं गए हैं int a[4]{1, 2, 3, 4}; int (&b)[4] = a;? रेफरेंस_वॉपर यहां खास नहीं है क्योंकि देशी काम T& करता है
अंडरस्कोर_डी

1
@AnkitAcharya हाँ :-) लेकिन सटीक होना करने के लिए, प्रभावी परिणाम अलग रूप में, खुद को केवल एक ही वस्तु को दर्शाता है। वैसे भी, आप बिल्कुल सही हैं कि एक सामान्य रेफ के विपरीत, wrapperएक कंटेनर में जा सकते हैं। यह आसान है, लेकिन मुझे लगता है कि लोग इसे गलत व्याख्या करते हैं क्योंकि यह वास्तव में अधिक उन्नत है। अगर मुझे 'refs' की एक सरणी चाहिए, तो मैं आम तौर पर बिचौलिये को छोड़ देता हूं vector<Item *>, जो कि wrapperफोड़े के नीचे है ... और उम्मीद है कि एंटी-पॉइंटर प्यूरिस्ट मुझे नहीं मिलेंगे। इसके लिए उपयोग के मामले अलग और अधिक जटिल हैं।
अंडरस्कोर_ड

1
"जब आप किसी ऑब्जेक्ट के संदर्भ का अनुकरण करना चाहते हैं तो एक reference_wrapper बहुत उपयोगी है जिसे कॉपी किया जा सकता है।" लेकिन क्या यह एक संदर्भ के उद्देश्य को नहीं हराता है? आप वास्तविक चीज़ की बात कर रहे हैं। यही एक संदर्भ है। एक संदर्भ जिसे कॉपी किया जा सकता है, व्यर्थ लगता है, क्योंकि अगर आप इसे कॉपी करना चाहते हैं, तो आप पहली जगह में एक संदर्भ नहीं चाहते हैं, आपको बस मूल ऑब्जेक्ट की प्रतिलिपि बनाना चाहिए। यह एक समस्या को हल करने के लिए जटिलता की एक अनावश्यक परत की तरह लगता है जिसे पहली जगह में मौजूद होने की आवश्यकता नहीं है।
स्टू

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को संग्रहीत किया गया है (मूल्य द्वारा लिया गया है) f1उस बिंदु पर इसे आरंभीकृत किया गया था, लेकिन f2एक std::reference_wrapperमूल्य रखा गया है, और इस तरह व्यवहार करता है जैसे कि इसमें लिया गया है int&


2
@CppNITR पक्का! एक छोटे से डेमो को इकट्ठा करने के लिए मुझे एक पल दें :)
क्वेंटिन

1
T & Ref (T)
CppNITR

3
@CppNITR std::ref(T)एक रिटर्न std::reference_wrapper। यह लिपटे हुए पॉइंटर की तुलना में थोड़ा अधिक है, लेकिन लाइब्रेरी द्वारा "हे, मुझे एक संदर्भ माना जा रहा है, कृपया मुझे एक बार फिर से एक बार फिर से चालू करें।"
क्वेंटिन

38

C ++ भाषा में एक संदर्भ ( T&या T&&) एक विशेष तत्व है। यह संदर्भ द्वारा किसी ऑब्जेक्ट को हेरफेर करने की अनुमति देता है और भाषा में विशेष उपयोग के मामले हैं। उदाहरण के लिए, आप संदर्भ रखने के लिए एक मानक कंटेनर नहीं बना सकते हैं: vector<T&>बीमार है और संकलन त्रुटि उत्पन्न करता है।

std::reference_wrapperदूसरी ओर A एक C ++ ऑब्जेक्ट है जो किसी संदर्भ को रखने में सक्षम है। जैसे, आप इसे मानक कंटेनरों में उपयोग कर सकते हैं।

std::refएक मानक कार्य है जो std::reference_wrapperअपने तर्क पर लौटता है । एक ही विचार में, एक कास्ट संदर्भ में std::crefलौटता std::reference_wrapperहै।

एक की एक दिलचस्प संपत्ति std::reference_wrapper, यह है कि यह एक है operator T& () const noexcept;। इसका मतलब है कि भले ही यह एक सच्ची वस्तु है , यह स्वचालित रूप से उस संदर्भ में परिवर्तित हो सकता है जो इसे धारण कर रहा है। इसलिए:

  • जैसा कि यह एक कॉपी असाइन करने योग्य ऑब्जेक्ट है, इसका उपयोग कंटेनरों में या अन्य मामलों में किया जा सकता है जहां संदर्भ की अनुमति नहीं है
  • इसके लिए धन्यवाद operator T& () const noexcept;, इसका उपयोग कहीं भी किया जा सकता है आप एक संदर्भ का उपयोग कर सकते हैं, क्योंकि यह स्वचालित रूप से इसमें परिवर्तित हो जाएगा।

1
जिसका मुख्य रूप से उल्लेख किया गया था, operator T& ()जिसके अन्य 2 उत्तर उल्लेख करने में विफल रहे।
मेटालैस्टर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.