2009-09-26 10 views
11

मैं 5 साल से अधिक समय में सी ++ में प्रोग्रामिंग कर रहा हूं, और कभी भी किसी भी स्थान से नहीं मिला है जहां चर के संदर्भ को छोड़कर उपयोग करने के लिए चर के संदर्भ की सिफारिश की जाती है (यदि आप जो भी पास करते हैं उसकी प्रतिलिपि बनाना नहीं चाहते हैं आपके फ़ंक्शन तर्क के रूप में)। तो क्या कोई ऐसे मामलों को इंगित कर सकता है जहां उपयोग करने के लिए सी ++ परिवर्तनीय संदर्भ की सिफारिश की जाती है (मेरा मतलब है कि यह कोई लाभ देता है)।सी ++ संदर्भ प्रकार अनुशंसित उपयोग

+1

क्या आपका मतलब सूचक के विपरीत है? –

उत्तर

15

एक अपारदर्शी संग्रह एक्सेसर/mutator

std::map की operator[] रिटर्न एक संदर्भ की एक वापसी मान के रूप में।


पाठ संदर्भ के लिए एक चर

आप ओल्ड-स्कूल छूट जाता है तो with Foo do ... बयान (कि पास्कल वाक्य रचना है) की जरूरत को छोटा करने के लिए, आप

MyString &name = a->very->long_->accessor->to->member; 
if (name.upcase() == "JOHN") { 
    name += " Smith"; 
} 

इस का एक और उदाहरण लिख सकते हैं Mike Dunlavey's answer


में पाया जा सकता है

राज्य के लिए है कि कुछ सिर्फ एक संदर्भ

संदर्भ भी आवरण वस्तुओं और functors में उपयोगी होते हैं है - यानी। मध्यवर्ती वस्तुओं में जो तार्किक रूप से किसी भी सदस्य से संपर्क नहीं करते हैं, लेकिन केवल संदर्भ उनके लिए।

उदाहरण:

class User_Filter{ 
    std::list<User> const& stop_list; 
    public: Functor (std::list<User> const& lst) 
    : stop_list(lst) { } 
    public: bool operator()(User const& u) const 
    { return stop_list.exists(u); } 
}; 

find_if(x.begin(),x.end(),User_Filter(user_list)); 

यहाँ विचार है कि यह एक संकलन त्रुटि अगर आप इस तरह के एक वस्तु के निर्माता में एक संदर्भ को प्रारंभ नहीं है। संकलन समय में अधिक जांच - बेहतर कार्यक्रम हैं।

1

मैं मानता हूँ के लिए करते हैं, लेकिन शायद स्थिरांक वापसी मान।

3

मैं फ़ंक्शंस तर्कों में संदर्भों का उपयोग न केवल प्रतियों से बचने के लिए बल्कि पॉइंटर्स के बजाय NULL पॉइंटर्स से निपटने से बचने के लिए उचित है। प्वाइंटर्स मॉडल "शायद एक मूल्य है, लेकिन शायद नहीं (NULL)", संदर्भ एक स्पष्ट बयान है कि एक मूल्य आवश्यक है।

... और यह बिल्कुल स्पष्ट बनाने के लिए (-> टिप्पणियाँ)। मैं पॉइंटर्स से मॉडल से बचने के लिए "शायद कई मूल्य हैं" - एक वेक्टर यहां एक बेहतर विकल्प है। कई मूल्यों के पॉइंटर्स अक्सर सी-स्टाइल प्रोग्रामिंग में समाप्त होते हैं क्योंकि आपको आमतौर पर तत्वों के # अलग-अलग पास करना पड़ता है।

+0

मैं मानता हूं कि नल मान के साथ संदर्भ होना संभव नहीं है लेकिन आप पॉइंटर्स के इंस्टेंट का उपयोग नहीं कर सकते हैं। पॉइंटर्स वास्तव में बहुत अलग बात है! – Narek

+2

पॉइंटर्स भी मॉडल "कई मूल्य हैं" हो सकता है। – UncleBens

+0

यह सही है, पॉइंटर्स के मुकाबले ज्यादा उपयोग होता है। हालांकि, अक्सर लोग दक्षता कारणों के लिए पॉइंटर्स पास करते हैं। मुझे ऊपर "जहां उचित" जोड़ा जाना चाहिए था। –

5

मैं बाहर से नियंत्रित गैर वैकल्पिक निर्माण मानकों के लिए संकेत के बजाय संदर्भ सदस्यों का उपयोग करते हैं।

संपादित करें (जोड़ा उदाहरण):

struct Database {}; 
struct PersonDao { 
    const Database &m_d; 
    PersonDao(const Database &d): m_d(d) {} 
}; 

इसके अलावा, डेटाबेस के दायरे बाह्य से नियंत्रित किया जाता है:

मान लीजिए कि आप एक डेटाबेस और एक डीएओ एक निर्भरता के रूप में डेटाबेस होने वर्ग है कि चलो डीएओ:

int main() { 
    Database d; 
    PersonDao pd(d); 
} 

इस मामले में यह समझ में आता है एक संदर्भ प्रकार का उपयोग करने के लिए, के बाद से आप कभी भी नहीं करना चाहती डीएओ :: m_d अशक्त होने के लिए, और अपने जीवनकाल exte नियंत्रित किया जाता है rnally (इस मामले में मुख्य समारोह से)।

+1

क्या आप कृपया एक उदाहरण देंगे? धन्यवाद। – pierrotlefou

+0

कोई समस्या नहीं, किया गया। –

+0

ठीक है, आप हमेशा 'PersonDao * Badboy() {डेटाबेस डी; नया पर्सनडाओ (डी) वापस करें; } ' –

1

अच्छी तरह से आपके पास अन्य मूल्यों को अलियासिंग करने के लिए दो विकल्प हैं (shared_ptrs और जैसा दिखाना): पॉइंटर्स और संदर्भ।

संदर्भ किसी अन्य चीज़ के संदर्भ में निर्माण पर प्रारंभ किए जाने चाहिए। तो अर्थात् एक संदर्भ कभी भी पूर्ण नहीं हो सकता है। हकीकत में, हालांकि, अंतर्निहित डेटा दूर जा सकता है, जिससे आपको पॉइंटर दूर जाने की तुलना में समस्याओं को डीबग करना मुश्किल हो जाता है। इसलिए मुझे यकीन नहीं है कि यहां तक ​​कि वास्तविक लाभ नहीं है जब तक कि आप अनुशासित और सुसंगत रूप से आवंटित वस्तुओं को संदर्भित करने के साथ-साथ उनका उपयोग कैसे करते थे। यदि आपने पॉइंटर्स के साथ भी ऐसा किया है, तो आप एक ही समस्या से बचेंगे।

शायद अधिक महत्वपूर्ण बात, पॉइंटर्स के साथ उत्पन्न होने वाले सभी मुद्दों के बारे में सोचने के बिना संदर्भों का उपयोग किया जा सकता है। यह शायद मुख्य लाभ है। अर्थात् एक संदर्भ बात है। यदि आप कॉलर/कैली के रूप में गारंटी देते हैं कि अंतर्निहित स्मृति दूर नहीं जाती है, तो आपको उपयोगकर्ता को पॉइंटर्स के साथ आने वाले किसी भी प्रश्न के साथ भ्रमित करने की आवश्यकता नहीं है (क्या मुझे इसे मुक्त करने की आवश्यकता है? क्या यह शून्य हो सकता है? आदि) और सुविधा के लिए एक संदर्भ का सुरक्षित रूप से उपयोग कर सकते हैं।

इस का एक उदाहरण एक समारोह है कि एक enum के लिए इसी स्ट्रिंग को खोजता है हो सकता है,

const std::string& ConvertToString(someEnum val) 
{ 
    static std::vector<std::string> lookupTable; 
    if (lookupTable.empty()) 
    { 
     // fill in lookup table 
    } 
    // ignoring the cast that would need to happen 
    return lookupTable[val] 
} 

यहाँ फोन करने वाले और कॉल प्राप्त करने वाला गारंटी देता है कि वापसी प्रकार हमेशा वहाँ हो जाएगा के बीच अनुबंध। आप सुरक्षित रूप से एक संदर्भ वापस कर सकते हैं, और पॉइंटर्स को आमंत्रित करने वाले कुछ प्रश्नों से बच सकते हैं।

+1

किसी भी दर पर संदर्भ और पॉइंटर्स के साथ डिबगिंग अलग नहीं है। जब तक आप ध्यान रखें कि संदर्भ संदर्भित _not_ है लेकिन उपनाम यह सूचक से अलग नहीं है। –

11

यहाँ एक मामला है जहां यह काम दिया गया है:

MyClass myArray[N]; 

for (int i = 0; i < N; i++){ 
    MyClass& a = myArray[i]; 
    // in code here, use a instead of myArray[i], i.e. 
    a.Member = Value; 
} 
+0

यह कहना है कि मैंने जो कुछ भी बताया है उसे छोड़कर इसका उपयोग केवल एलियासिंग के लिए किया जा रहा है। :-) – Narek

+8

@ नरेक: हुन ?? –

1

संदर्भ कोड खूबसूरत बनाते हैं। इसलिए जब भी यह आपके कोड को सुशोभित करने का संदर्भ लेता है तो उनका उपयोग करें।

0

मैं कुछ मामलों भर्ती करना चाहते हैं: सिंगलटन कक्षाएं

class singleton 
    { 
     singleton(); 
     explicit singleton(const singleton&); 
     singleton& operator=(const singleton&); 
    public: 
     static singleton& instance() 
     { 
      static singleton inst; 
      return inst; 
     } 
    };// this is called the 'Meyers' singleton pattern. refer to More Effective C++ by Scott Meyers 

यह सभी लाभ है लेखन लेकिन नए ऑपरेटर

** 2 का उपयोग कर टाल जबकि

1)) ** यहां एक शून्य संदर्भ के रूप में ऐसी कोई बात नहीं है। एक संदर्भ हमेशा कुछ वस्तु को संदर्भित करना चाहिए। नतीजतन, यदि आपके पास एक वेरिएबल है जिसका उद्देश्य किसी अन्य ऑब्जेक्ट को संदर्भित करना है, लेकिन यह संभव है कि किसी ऑब्जेक्ट को संदर्भित न किया जाए, तो आपको चर को एक पॉइंटर बनाना चाहिए, क्योंकि तब आप इसे शून्य पर सेट कर सकते हैं। दूसरी तरफ, यदि चर हमेशा एक ऑब्जेक्ट का संदर्भ लेना चाहिए, यानी, यदि आपका डिज़ाइन संभावना के लिए अनुमति नहीं देता है कि चर शून्य है, तो आपको संभवतया चर को संदर्भ

** 3) ** क्योंकि एक संदर्भ एक वस्तु का उल्लेख करना चाहिए, सी ++ की आवश्यकता है कि संदर्भ प्रारंभ:

string& rs;    // error! References must 
          // be initialized 

    string s("xyzzy"); 

    string& rs = s;   // okay, rs refers to s 

Pointers are subject to no such restriction 

तथ्य एक अशक्त संदर्भ के रूप में ऐसी कोई बात नहीं है कि तात्पर्य यह एक से अधिक संकेत का उपयोग करने के संदर्भ का उपयोग करने के लिए कुशल हो सकता है।ऐसा इसलिए है क्योंकि

** 4) ** पॉइंटर्स और संदर्भों के बीच एक और महत्वपूर्ण अंतर यह है कि विभिन्न ऑब्जेक्ट्स को संदर्भित करने के लिए पॉइंटर्स को फिर से सौंप दिया जा सकता है। ¤ मद एम 1, P10

string s1("Nancy"); 
    string s2("Clancy"); 

    string& rs = s1;   // rs refers to s1 

    string *ps = &s1;  // ps points to s1 

    rs = s2;     // rs still refers to s1, 
          // but s1's value is now 
          // "Clancy" 

    ps = &s2;    // ps now points to s2; 
          // s1 is unchanged 
+0

मैं उनसे टिप्पणियों की अपेक्षा कर रहा था जो सहमत नहीं हैं :( – Satbir

0

मैं एक सूचक के बजाय एक ostream के लिए एक संदर्भ का उपयोग किया है: एक संदर्भ है, तथापि, हमेशा वस्तु जिसके साथ यह आरंभ नहीं हो जाता को दर्शाता है। मुझे लगता है कि कक्षा में बहुत सारे ऑपरेटर होने पर मैं पॉइंटर्स के संदर्भ पसंद करता हूं।

3

एक नाम एक मूल्य के लिए, उदाहरण के लिए: यह नाम मूल्य देने के लिए .:

const Vec3 &ba=b-a; 

एक स्थिरांक संदर्भ का उपयोग करें, लेकिन जरूरी नहीं कि इसके लिए एक चर पैदा नहीं करता। सिद्धांत रूप में, यह संकलक को अधिक छूट देता है और इसे कुछ प्रतिलिपि कन्स्ट्रक्टर कॉल से बचने की अनुमति दे सकता है।

(संबंधित गैर दोहराया Const reference to temporary पर स्टैक ओवरफ़्लो सवाल। हर्ब Sutter लिंक वहाँ इस बारे में अधिक जानकारी नहीं है।)

+0

दिलचस्प, आपको यह नहीं पता था कि आप ऐसा कर सकते हैं। –

+0

हा, मुश्किल! यह नहीं पता था। :-) –

3

कॉपी-निर्माता के लिए तर्क, एक संदर्भ के रूप में पारित किया जाना चाहिए अन्यथा के बाद से प्रति निर्माता इसे एक अंतहीन रिकर्सन (ढेर ओवरफ्लो) में स्वयं को कॉल करने की आवश्यकता होगी।

1

स्ट्रीम ऑपरेटरों एक स्पष्ट उदाहरण

std::ostream & operator<< (std::ostream &, MyClass const &...) { 
    .... 
} 

mystream << myClassVariable; 

आप स्पष्ट रूप से एक सूचक नहीं करना चाहती के रूप में शून्य के लिए जाँच एक ऑपरेटर बहुत कठिन i.s.o. का उपयोग कर बनाता हैं सुविधाजनक

8

जहां चाहें संदर्भों का उपयोग करें, पॉइंटर्स जब आपको मजबूर होना पड़ता है।

संदर्भ और पॉइंटर्स अपने अर्थशास्त्र का हिस्सा साझा करते हैं: वे मौजूद तत्व के लिए उपनाम हैं जो मौजूद नहीं हैं। मुख्य अंतर स्मृति प्रबंधन के साथ है: संदर्भ स्पष्ट रूप से व्यक्त करते हैं कि आप संसाधन के लिए ज़िम्मेदार नहीं हैं। दूसरी तरफ, पॉइंटर्स के साथ यह वास्तव में कभी स्पष्ट नहीं होता है (जब तक कि आप स्मार्ट पॉइंटर्स का मतलब न लें): क्या आप पॉइंटर को हटाना चाहते हैं या इसे बाहरी रूप से हटा दिया जाएगा?

आपको पॉइंटर्स का उपयोग करना होगा जब आपको स्मृति का प्रबंधन करना होगा, वैकल्पिक अर्थशास्त्र के लिए अनुमति देना चाहते हैं या बाद में निर्दिष्ट तत्व को बदलने की आवश्यकता है।

शेष मामलों में, जहां आप संदर्भ या सूचक का उपयोग कर सकते हैं, संदर्भ स्पष्ट हैं और उन्हें प्राथमिकता दी जानी चाहिए।

अब, जैसा कि आप इंगित करते हैं, उन्हें वास्तव में जरूरी नहीं है: आप हमेशा सभी संदर्भ उपयोगों (यहां तक ​​कि पैरामीटर गुजरने) के लिए पॉइंटर्स का उपयोग कर सकते हैं, लेकिन तथ्य यह है कि आप सब कुछ के लिए एक उपकरण का उपयोग कर सकते हैं इसका मतलब यह नहीं है कि वहां हैं नौकरी के लिए कोई बेहतर अनुकूल उपकरण नहीं।

+0

मैं पूरी तरह से आपके तर्क से सहमत हूं, लेकिन बस जोड़ना चाहता था कि केवल वैकल्पिक अर्थशास्त्र के लिए आप बूस्ट :: वैकल्पिक http://www.boost.org/doc/libs/1_40_0/libs/optional/doc/html/index.html का भी उपयोग कर सकते हैं – Pieter

संबंधित मुद्दे