C ++ में पॉइंटर्स के संदर्भ में पासिंग


130

जहाँ तक मैं बता सकता हूँ, कोई कारण नहीं है कि मुझे C ++ में एक पॉइंटर के संदर्भ को पारित करने की अनुमति नहीं दी जानी चाहिए। हालाँकि, ऐसा करने के मेरे प्रयास विफल हो रहे हैं, और मुझे पता नहीं क्यों।

यह मैं क्या कर रहा हूँ:

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}

और मुझे यह त्रुटि मिल रही है:

पैरामीटर 1 को 'std :: string *' से 'std :: string * &' में नहीं बदल सकते।

जवाबों:


126

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

string s;
string* _s = &s;
myfunc(_s);

बस ठीक संकलन करना चाहिए।

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


86

समस्या यह है कि आप संदर्भ के लिए एक अस्थायी बाध्य करने का प्रयास कर रहे हैं, जो C ++ जब तक संदर्भ नहीं है अनुमति नहीं देता है const

तो आप निम्न में से एक कर सकते हैं:

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}


void myfunc2(string* const& val)
{
    // Do stuff to the string pointer
}

int main()
// sometime later 
{
    // ...
    string s;
    string* ps = &s;

    myfunc( ps);   // OK because ps is not a temporary
    myfunc2( &s);  // OK because the parameter is a const&
    // ...

    return 0;
}

- यह प्रकार जिस तरह से श्री बर उदाहरण नं .2 में करता है को लिखने के लिए विशेष रूप से शिक्षाप्रद है string* const& valजैसे की तरह एक कम सुपाठ्य बराबर के बजाय const string* &val। मेरी नजर में यह स्पष्ट रूप से एक तार के लिए, एक पॉइंटर को, एक कॉस्ट रेफरेंस है । मैं व्यक्तिगत रूप से इस सटीक स्पष्टीकरण को प्राप्त करने के लिए घोषणाओं के T const&बजाय लिखना पसंद करता हूं const T&
फिश २००

1
नित पिक (आलोचना नहीं): मेरे लिए, वाक्यांश bind a temporary to the referenceइस उत्तर में @Chris की तुलना में स्पष्ट है reference to an actual string pointer in the calling scope, not an anonymous string pointer। बावजूद, दोनों ही मेरे दृष्टिकोण से सही हैं।
केविनरपे

1
@ fish2000 केवल इतना ही नहीं है, const string*&और string* const&वास्तव में विभिन्न प्रकार हैं। पहला एक गैर- constसंदर्भ है const string*, जबकि दूसरा एक constसंदर्भ है string*
जस्टिन टाइम -

@ fish2000 "पसंद" T const&से सावधान रहें const T&- जैसा कि @ जस्टिन टाइम बताते हैं, वे अलग-अलग प्रकार के हैं। इसका कभी-कभी कोई परिणाम नहीं हो सकता है, लेकिन अन्य स्थितियों में यह एक या दूसरे को पसंद करने के लिए बिल्कुल महत्वपूर्ण होगा, बहुत पसंद intकरना double
ओमाताई

3
@ fish2000 - एक कहता है "यहां एक संदर्भ है जिसे आप कुछ बदल सकते हैं जिसे आप बदल नहीं सकते हैं" जबकि दूसरा कहता है "यहां एक संदर्भ आपको बदल नहीं सकता है"। दिए गए इस उदाहरण में, आप बस दोनों को इंटरचेंज नहीं कर सकते हैं।
ओमाताई

10

इसे इसमें बदलें:

  std::string s;
  std::string* pS = &s;
  myfunc(pS);

संपादित करें:

इसे कहा जाता है ref-to-pointerऔर आप फ़ंक्शन के संदर्भ के रूप में अस्थायी पते को पास नहीं कर सकते। (जब तक यह नहीं है const reference)।

हालाँकि, मैंने दिखाया है std::string* pS = &s;(एक स्थानीय चर के लिए सूचक), इसका विशिष्ट उपयोग होगा: जब आप चाहते हैं कि कैली पॉइंटर को स्वयं बदल दे, न कि वह वस्तु जो वह इंगित करता है। उदाहरण के लिए, एक फ़ंक्शन जो मेमोरी आवंटित करता है और अपने तर्क को आवंटित मेमोरी ब्लॉक का पता बताता है, उसे पॉइंटर या पॉइंटर से पॉइंटर का संदर्भ लेना चाहिए:

void myfunc(string*& val)
{
//val is valid even after function call
   val = new std::string("Test");

}

5

&s स्ट्रिंग के लिए अस्थायी पॉइंटर का उत्पादन करता है और आप अस्थायी ऑब्जेक्ट का संदर्भ नहीं बना सकते हैं।


4
यह बिल्कुल सच नहीं है - आप अस्थायी के लिए एक संदर्भ बना सकते हैं
1800 सूचना

3

प्रयत्न:

void myfunc(string& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(s);
    // ...
}

या

void myfunc(string* val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}

हालांकि मैं जो कर रहा हूं उसके लिए मुझे सूचक के साथ-साथ सूचक के पते की भी आवश्यकता है। मैं सूचक को मान से पास नहीं करना चाहता।
एलेक्स

फिर भी समझ में नहीं आता कि आप क्या हासिल करने की कोशिश करते हैं। आपके पास "स्ट्रिंग s" के "पॉइंटर का पता" नहीं हो सकता है, केवल इसलिए कि "स्ट्रिंग एस" एक पॉइंटर नहीं है।
Sake

@ एलेक्स: मैं इसे लेता हूं कि आपको यह पता लगाने की आवश्यकता है कि क्या स्ट्रिंग बिल्कुल उसी तरह है जैसे आप स्टोर कर रहे हैं और न कि क्या उनकी सामग्री समान है। अगर ऐसा है, तो ध्यान दें कि आप एक पते के लिए ऑपरेटर के पते का उपयोग कर सकते हैं और यह आपको संदर्भित वस्तु का पता मिलेगा: void f (std :: string const & s) {std :: string const * p = & s; }
डेविड रोड्रिगेज -

3

संपादित करें: मैंने कुछ प्रयोग किया है, और खोज की गई चीज मेरे विचार से थोड़ी सूक्ष्म है। यहाँ अब मुझे लगता है कि एक सटीक उत्तर है।

&sजब तक संदर्भ का प्रकार संदर्भ नहीं होता है, तब तक आप एक संदर्भ नहीं बनाते हैं const। उदाहरण के लिए, आप ऐसा नहीं कर सकते

string * &r = &s;

लेकिन आप कर सकते हैं

string * const &r = &s;

यदि आप फ़ंक्शन हेडर में इसी तरह की घोषणा करते हैं, तो यह काम करेगा।

void myfunc(string * const &a) { ... }

वहाँ एक और मुद्दा है, अर्थात्, अस्थायी। नियम यह है कि आप अस्थायी का संदर्भ तभी प्राप्त कर सकते हैं जब वह हो const। तो इस मामले में कोई यह तर्क दे सकता है कि एक अस्थायी है, और इसलिए घोषित किया जाना चाहिएconst फ़ंक्शन प्रोटोटाइप में किया । व्यावहारिक दृष्टिकोण से इस मामले में कोई फर्क नहीं पड़ता है। (यह या तो एक प्रतिद्वंद्विता या अस्थायी है। किसी भी तरह, एक ही नियम लागू होता है।) हालांकि, कड़ाई से बोलते हुए, मुझे लगता है कि यह एक अस्थायी नहीं बल्कि एक प्रतिद्वंद्विता है। मुझे आश्चर्य है कि क्या दोनों के बीच अंतर करने का कोई तरीका है। (शायद यह सीधे तौर पर परिभाषित किया गया है कि सभी अस्थायी व्यवस्थाएं हैं, और सभी गैर-भाषाएं अस्थायी हैं। मैं मानक पर विशेषज्ञ नहीं हूं।)

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

string *p = &s;
myfunc(p);

यदि आप sकिसी पॉइंटर या पॉइंटर का संदर्भ चाहते हैं s, तो सीधी बात करें।


1

मैंने बस रूट को छोड़कर हटाए गए बाइनरी ट्री में सभी पॉइंटर्स बनाने के लिए एक पॉइंटर के संदर्भ का उपयोग किया है। पॉइंटर को सुरक्षित बनाने के लिए हमें बस इसे 0. पर सेट करना होगा। मैं उस फ़ंक्शन को नहीं बना सका जो पेड़ को हटाता है (केवल रूट को) एक पॉइंटर को रेफरी स्वीकार करने के लिए क्योंकि मैं रूट (इस पॉइंटर) को पहले के रूप में उपयोग कर रहा हूं बाएं और दाएं पार करने के लिए इनपुट।

void BinTree::safe_tree(BinTree * &vertex ) {
    if ( vertex!=0 ) {  // base case
        safe_tree(vertex->left);    // left subtree.
            safe_tree(vertex->right);   //  right subtree.
          // delete vertex;  // using this delete causes an error, since they were deleted on the fly using inorder_LVR. If inorder_LVR does not perform delete to the nodes, then, use delete vertex;
        vertex=0;  // making a safe pointer
    }
} // end in

निचला रेखा, एक पॉइंटर का संदर्भ अमान्य है जब औपचारिक पैरामीटर (यह) पॉइंटर है।


1

C ++ 11 में आपका स्वागत है और संदर्भ देखें:

#include <cassert>
#include <string>

using std::string;

void myfunc(string*&& val)
{
    assert(&val);
    assert(val);
    assert(val->c_str());
    // Do stuff to the string pointer
}

// sometime later 
int main () {
    // ...
    string s;
    myfunc(&s);
    // ...
}

अब आपके पास पॉइंटर के मूल्य (द्वारा संदर्भित) तक पहुंच है val ) , जो स्ट्रिंग का पता है।

आप सूचक को संशोधित कर सकते हैं, और कोई भी परवाह नहीं करेगा। यह एक पहलू है कि पहले स्थान पर एक प्रतिद्वंद्विता क्या है।

सावधान रहें: पॉइंटर का मूल्य केवल myfunc()रिटर्न तक ही मान्य है। आखिर में, यह एक अस्थायी है।


-1

मुझे पता है कि यह संकेत के संदर्भों को पारित करने के लिए पॉसिबल है, मैंने इसे पिछले हफ्ते किया था, लेकिन मुझे याद नहीं है कि वाक्यविन्यास क्या था, क्योंकि आपका कोड अभी मेरे मस्तिष्क के लिए सही दिखता है। हालाँकि एक और विकल्प पॉइंटर्स पॉइंटर्स का उपयोग करना है:

Myfunc(String** s)

-8

myfunc ("string * & val") इसका खुद कोई मतलब नहीं है। "स्ट्रिंग * और वैल" का अर्थ है "स्ट्रिंग वैल", * और & एक दूसरे को रद्द करना। अंत में एक फ़ंक्शन ("स्ट्रिंग वैल") के लिए स्ट्रिंग चर को पेस नहीं किया जा सकता है। किसी फ़ंक्शन के लिए केवल मूल डेटा प्रकारों को पारित किया जा सकता है, अन्य डेटा प्रकारों के लिए पॉइंटर या संदर्भ के रूप में पास करने की आवश्यकता होती है। आपके पास एक फ़ंक्शन के लिए स्ट्रिंग या वैल या स्ट्रिंग * वैल हो सकता है।


4
सभी स्तरों पर गलत। कृपया अपना var घोषणा सिंटैक्स ताज़ा करें।
अरी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.