2010-08-31 16 views
41

आम हालात:संदर्भ द्वारा कब पास किया जाए और सी ++ में पॉइंटर द्वारा कब पास किया जाए?

  1. एक समारोह foo (std :: स्ट्रिंग *) या foo (std :: स्ट्रिंग &) को पासिंग std :: स्ट्रिंग;
  2. पासिंग tr1 :: shared_ptr को फ़ंक्शन foo (tr1 :: shared_ptr * ptr) या foo (tr1 :: shared_ptr & ptr);

सामान्य रूप से, एक अच्छा अभ्यास क्या है। मैं हमेशा भ्रमित हो जाता हूं। सबसे पहले, संदर्भों के रूप में सब कुछ गुजरना लगातार लगता है, हालांकि संदर्भों के संदर्भ में संदर्भों या एनयूएलएल के रूप में पारित करना संभव नहीं है।

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

क्या आपको लगता है कि निम्न स्निपेट अच्छा है?

#include <iostream> 
#include <vector> 
#include <map> 
#include <string> 
#include <tr1/memory> 
#include <algorithm> 
using namespace std; 
using namespace std::tr1; 

int main(){ 
     map<string, shared_ptr<vector<string> > > adjacencyMap; 
     vector<string>* myFriends = new vector<string>(); 
     myFriends->push_back(string("a")); 
     myFriends->push_back(string("v")); 
     myFriends->push_back(string("g")); 
     adjacencyMap["s"] = shared_ptr<vector<string> >(myFriends); 
     return 0; 
} 

धन्यवाद अजय

+0

'foo (tr1 :: shared_ptr * पीआरटी) 'यह मेरी राय में अच्छे डिजाइन के परिप्रेक्ष्य से बहुत गलत लगता है। आप निरंतर संदर्भों के बारे में जानते हैं? – Anycorn

+3

आप 'myFriends' को तुरंत स्मार्ट पॉइंटर में क्यों नहीं डालते? – GManNickG

+2

मुझे लगता है कि यह एक डुप्लिकेट है [सी ++ में कार्यों को ऑब्जेक्ट कैसे पास करें?] (Http: // stackoverflow।कॉम/प्रश्न/2139224/कैसे-टू-पास-ऑब्जेक्ट-टू-फ़ंक्शंस-इन-सी), जहां मैंने पहले से ही सामान्य प्रश्न का उत्तर दिया है। – sbi

उत्तर

23

संदर्भ सही होने के लिए आसान हैं।

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

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

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

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

1

मैं

map<string, shared_ptr<vector<string> > > adjacencyMap; 
    shared_ptr<vector<string> > myFriends(new vector<string>()); 
    myFriends->push_back(string("a")); 
    myFriends->push_back(string("v")); 
    myFriends->push_back(string("g")); 
    adjacencyMap["s"] = myFriends; 
    return 0; 

पसंद करेंगे, क्योंकि यह आपके स्थानीय वर हैंडलिंग सुनिश्चित करता है अपवाद-सुरक्षित है।

मैं वास्तव में नहीं देखता कि यह आपके क्यू को कैसे संबोधित करता है जो रेफ बनाम पीआरटी की योग्यता के बारे में था। आपके द्वारा बताए गए दोनों उदाहरणों में मैं दूसरे (रेफरी) फॉर्म का उपयोग करने की अपेक्षा करता हूं।

2

आप कुछ अंतर्दृष्टि के लिए http://www.cplusplus.com/forum/beginner/3958/ ब्राउज़ कर सकते हैं। भी उपयोगी: http://www.velocityreviews.com/forums/t284603-pointers-vs-references-a-question-on-style.html

मुझे लगता है कि कोई "सही" उत्तर नहीं है। आपको अपनी परियोजना के विशिष्ट संदर्भ को ध्यान में रखते हुए प्रत्येक दृष्टिकोण के वजन और विपक्ष को कम करने की आवश्यकता है।

मैं व्यक्तिगत रूप से संदर्भ पसंद करता हूं, लेकिन मैं उन पदों को पढ़ने और इसके बारे में पढ़ने के लिए किसी भी तरह की सलाह देता हूं।

2

अंगूठे के सामान्य नियम के रूप में, हमेशा कॉन्स्ट के संदर्भ में पैरामीटर को पारित करने का प्रयास करें। पासिंग पॉइंटर्स स्वामित्व के मुद्दों के साथ-साथ सूक्ष्म गलतियों के लिए अन्य संभावनाओं का एक समूह भी ले सकते हैं।

न्यूल का उद्देश्य क्या है? एक अमान्य सूचक/वस्तु को इंगित करने के लिए। यदि आप किसी फ़ंक्शन में अमान्य ऑब्जेक्ट्स पास करने जा रहे हैं, तो आपको केवल ऑब्जेक्ट की वैधता की जांच करने के लिए एक विधि है। में के रूप में:

void myfunc(const obj& myobj) 
{ 
    if(myobj.valid()) 
    // DO SOMETHING 
} 

आदिम प्रकार आप आमतौर पर पारित-दर-मूल्य के लिए वैसे भी, वहाँ के बाद से इस तरह के छोटे से भूमि के ऊपर चाहेंगे। और वह तब होता है जब आप ज्यादातर समय शाब्दिक साहित्य का उपयोग करेंगे। तारों के लिए, आपको std::string का उपयोग करने का प्रयास करना चाहिए और const char* सी-स्टाइल स्ट्रिंग्स जितना संभव हो उतना दूर रहना चाहिए। बेशक यदि आपको सी-स्ट्रिंग का उपयोग करना है, तो आपके पास पॉइंटर्स का उपयोग करने के अलावा कोई विकल्प नहीं है, लेकिन सभी संदर्भों में सभी को जाने का तरीका होना चाहिए।

ओह और इस से बचने के लिए सही मायने में अपवाद-सुरक्षित कोशिश हो:

vector<string>* myFriends = new vector<string>(); 
... 
adjacencyMap["s"] = shared_ptr<vector<string> >(myFriends); 

इसके बजाय कार्य करें: क्यों यह पसंदीदा तरीका है के लिए आरए II और अपवाद सुरक्षा करने के लिए

shared_ptr<vector<string> > myFriends(new vector<string>()); 

देखो।

3

मेरे पिछले काम में, हमारे पास यह नियम था कि सादे संदर्भों का व्यावहारिक रूप से उपयोग नहीं किया गया था। मूल्य द्वारा (

  • पारित करने के लिए const संदर्भ द्वारा
  • पास (कॉपी करने के लिए सस्ते वस्तुओं, सभी पुरातन, छोटे मूल्य प्रकार, std :: स्ट्रिंग , बहुत छोटे या refcounted स्ट्रिंग्स के लिए): इसके बजाय हम पर सहमति बड़ी वस्तुओं को पढ़ने के लिए पहुंच)
  • सूचक द्वारा पारित अगर आप रीड-राइट पहुंच

तो हर कोई इन नियमों का पालन करती जरूरत है, तो आप मान सकते हैं कि कार्यों के लिए पारित पैरामीटर संशोधित नहीं कर रहे हैं जब तक उनका पता लिया गया था। यह हमारे लिए काम किया।

+0

मूल्य से std :: स्ट्रिंग क्यों पास करें? कॉन्स संदर्भ द्वारा होना चाहिए। आपको रीड-राइट एक्सेस करने पर भी डिफ़ॉल्ट रूप से संदर्भ से पास होना चाहिए। – ronag

+0

यदि आप फ़ंक्शन के भीतर एक आदिम को संशोधित करना चाहते हैं तो क्या होगा? आप इस मामले को कैसे संतुष्ट करते हैं? – user855

+0

+1, बहुत समझदार। @aja पॉइंटर द्वारा पास (संख्या 3) @ron संख्या 2 ऐसा कहता है। "चाहिए" वास्तव में वरीयता का मामला है – Anycorn

3

शायद प्रश्न का उत्तर नहीं है। केवल चूमो।

int main() 
{ 
     multimap<string, string> adjacencyMap; 
     adjacencyMap.insert(std::make_pair("s", "a")); 
     adjacencyMap.insert(std::make_pair("s", "v")); 
     adjacencyMap.insert(std::make_pair("s", "g")); 
     return 0; 
} 
+0

धन्यवाद! हालांकि यह मेरे प्रश्न का उत्तर नहीं देता है, मुझे मल्टीमैप के बारे में पता नहीं था। और यह उपयोग इस मामले के लिए बहुत उपयुक्त लगता है। – user855

+0

एक तरफ, ध्यान दें कि इस दृष्टिकोण में एक स्मृति हिट लगता है। एक मल्टीमैप का उपयोग करते समय एक ही कुंजी बार-बार कई बार संग्रहीत होती है। मेरे appraoch में, चूंकि कुंजी अद्वितीय हैं, वे केवल एक बार संग्रहीत हैं और अंतरिक्ष उपयोग कम है। इस पर कोई विचार? – user855

+0

कार्यान्वयन विशिष्ट है। मेरा मानना ​​है कि अधिकांश कार्यान्वयन एक बार डालने के बाद केवल एक ही कुंजी स्टोर करते हैं। – ronag

22

अंगूठे का एक अच्छा नियम: "संदर्भों का उपयोग करें जब आप कर सकते हैं और पॉइंटर्स जब आपको करना है"।

4

मैं सच में समझ में नहीं आता कि आपको यह सब परेशान करने के लिए मिल गया:

std::map < std::string, std::vector<std::string> > adjacencyMap; 
std::vector<std::string>& sFriends = adjacencyMap["s"]; 
sFriends.push_back("a"); 
sFriends.push_back("v"); 
sFriends.push_back("g"); 

आप shared_ptr यहाँ के साथ क्यों दखल करते हैं? स्थिति निश्चित रूप से इसके लिए फोन नहीं करता है!

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