C ++ में "int & foo ()" का क्या अर्थ है?


114

पढ़ते समय यह स्पष्टीकरण lvalues और rvalues पर, कोड की इन पंक्तियों में मेरे लिए बाहर अटक:

int& foo();
foo() = 42; // OK, foo() is an lvalue

मैंने इसे g ++ में आज़माया, लेकिन कंपाइलर "foo () के लिए अपरिभाषित संदर्भ" कहता है। अगर मैं जोड़ूं

int foo()
{
  return 2;
}

int main()
{
  int& foo();
  foo() = 42;
}

यह ठीक संकलन करता है, लेकिन इसे चलाने से एक विभाजन दोष होता है । बस रेखा

int& foo();

अपने आप में दोनों संकलन करता है और बिना किसी समस्या के चलता है।

इस कोड का क्या अर्थ है? आप एक फ़ंक्शन कॉल के लिए एक मूल्य कैसे निर्दिष्ट कर सकते हैं, और यह एक प्रतिद्वंद्विता क्यों नहीं है?


25
आप किसी फ़ंक्शन कॉल के लिए मान निर्दिष्ट नहीं कर रहे हैं, आप उस संदर्भ के लिए एक मान निर्दिष्ट कर रहे हैं जो यह देता है
Frédéric Hamidi

3
@ Frédéric Hamidi उस ऑब्जेक्ट का मान प्रदान करता है जिसे लौटाया गया संदर्भ संदर्भित कर रहा है
एमएम

3
हाँ यह वस्तु के लिए एक उपनाम है; संदर्भ वस्तु नहीं है
एमएम

2
@RoyFalk स्थानीय समारोह घोषणाएं एक पॉक्स हैं, व्यक्तिगत रूप से मैं उन्हें भाषा से हटाकर खुश हूं। (पाठ्यक्रम के लंबोदर को छोड़कर)
MM

4
इसके लिए पहले से ही जीसीसी बग है
15

जवाबों:


168

स्पष्टीकरण यह मान रहा है कि कुछ उचित कार्यान्वयन है fooजिसके लिए एक वैध के लिए एक संदर्भ अंतराल देता है int

ऐसा कार्यान्वयन हो सकता है:

int a = 2; //global variable, lives until program termination

int& foo() {
    return a;
} 

अब, क्योंकि fooएक अंतराल संदर्भ देता है, हम रिटर्न मान के लिए कुछ असाइन कर सकते हैं, जैसे:

foo() = 42;

यह aमान के साथ वैश्विक को अपडेट करेगा 42, जिसे हम सीधे चर पर पहुंचकर या fooफिर कॉल करके जांच सकते हैं :

int main() {
    foo() = 42;
    std::cout << a;     //prints 42
    std::cout << foo(); //also prints 42
}

ऑपरेटर के रूप में उचित []? या कुछ अन्य सदस्य विधियों का उच्चारण करते हैं?
Jan Dorniak

8
Refrences के बारे में भ्रम को देखते हुए, नमूनों से स्थिर स्थानीय चर निकालना संभवतः सबसे अच्छा है। इनिशियलाइज़ेशन अनावश्यक जटिलता जोड़ता है, जो सीखने के लिए एक बाधा है। बस इसे एक वैश्विक बनाएं।
मूइंग डक

72

अन्य सभी उत्तर फ़ंक्शन के अंदर एक स्टेटिक की घोषणा करते हैं। मुझे लगता है कि आपको भ्रमित कर सकता है, इसलिए इस पर एक नज़र डालें:

int& highest(int  & i, int  & j)
{
    if (i > j)
    {
        return i;
    }
    return j;
}

int main()
{
    int a{ 3};
    int b{ 4 };
    highest(a, b) = 11;
    return 0;
}

क्योंकि highest()एक संदर्भ देता है, आप इसके लिए एक मूल्य प्रदान कर सकते हैं। जब यह चलता है, तो इसे b11 में बदल दिया जाएगा। यदि आपने आरंभीकरण को बदल दिया है, तो यह aकहें कि 8, तो a11 में बदल जाएगा। यह कुछ कोड है जो वास्तव में अन्य उदाहरणों के विपरीत, एक उद्देश्य की सेवा कर सकते हैं।


5
क्या int a = 3 के बजाय int {{3} लिखने का कारण है? यह वाक्य-विन्यास मुझे उचित नहीं लगता।
अलेक्सी पेट्रेंको

6
@AlexPetrenko यह सार्वभौमिक आरंभ है। मैं उस उदाहरण का उपयोग कर रहा था जो मेरे पास था। इसके बारे में कुछ भी अनुचित नहीं है
केट ग्रेगोरी

3
मुझे पता है कि यह क्या है। a = 3 बस इतना क्लीनर लगता है। व्यक्तिगत वरीयता)
अलेक्सी पेट्रेंको

जैसे किसी फंक्शन के अंदर स्टेटिक की घोषणा करना कुछ लोगों को भ्रमित कर सकता है, मेरा यह भी मानना ​​है कि यूनिवर्सल इनिशियलाइजेशन का उपयोग करने की संभावना है।
एरिकसर्टिन

@AlekseiPetrenko int = 1.3 के मामले में, यह स्पष्ट रूप से a = 1. में परिवर्तित होता है। जबकि int {a {1.3} का परिणाम त्रुटि है: रूपांतरण संकीर्ण।
सात्विक

32
int& foo();

फू नामक एक फ़ंक्शन की घोषणा करता है जो एक संदर्भ देता है a int। जो उदाहरण करने में विफल रहता है वह आपको उस फ़ंक्शन की परिभाषा देता है जिसे आप संकलित कर सकते हैं। अगर हम उपयोग करते हैं

int & foo()
{
    static int bar = 0;
    return bar;
}

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

foo() = 42;

क्या होता है हम 42 को असाइन करते हैं barक्योंकि हम संदर्भ को असाइन करते हैं और संदर्भ केवल एक उपनाम है bar। यदि हम फ़ंक्शन को फिर से पसंद करते हैं

std::cout << foo();

जब हम barउस से ऊपर सेट करते हैं, तो यह 42 का होगा ।


15

int &foo();foo()रिटर्न प्रकार के साथ एक फ़ंक्शन घोषित करता हैint& । यदि आप एक शरीर प्रदान किए बिना इस फ़ंक्शन को कॉल करते हैं तो आपको एक अपरिभाषित संदर्भ त्रुटि मिलने की संभावना है।

अपने दूसरे प्रयास में आपने एक फ़ंक्शन प्रदान किया int foo()। इसके द्वारा घोषित फ़ंक्शन के लिए एक अलग रिटर्न प्रकार है int& foo();। तो आपके पास उसी की दो घोषणाएं हैं fooजो मेल नहीं खाती हैं, जो अपरिभाषित व्यवहार (कोई नैदानिक ​​विश्लेषण) के कारण वन डेफिनिशन नियम का उल्लंघन करती है।

जो कुछ काम करता है, उसके लिए स्थानीय फ़ंक्शन घोषणा को बाहर निकालें। वे चुप अपरिभाषित व्यवहार के लिए नेतृत्व कर सकते हैं जैसा कि आपने देखा है। इसके बजाय, किसी भी फ़ंक्शन के बाहर केवल फ़ंक्शन घोषणाओं का उपयोग करें। आपका कार्यक्रम जैसा दिख सकता है:

int &foo()
{
    static int i = 2;
    return i;
}  

int main()
{
    ++foo();  
    std::cout << foo() << '\n';
}

10

int& foo();एक संदर्भ के लिए एक समारोह लौट रहा है int। आपके प्रदान किए गए फ़ंक्शन रिटर्न intबिना संदर्भ के।

आप कर सकते हैं

int& foo()
{
    static int i = 42;
    return i;
}

int main()
{
    int& foo();
    foo() = 42;
}

7

int & foo();इसका मतलब है कि foo()एक चर का संदर्भ देता है।

इस कोड पर विचार करें:

#include <iostream>
int k = 0;

int &foo()
{
    return k;
}

int main(int argc,char **argv)
{
    k = 4;
    foo() = 5;
    std::cout << "k=" << k << "\n";
    return 0;
}

यह कोड प्रिंट करता है:

$ ./a.out k = 5

क्योंकि foo()वैश्विक चर का संदर्भ देता है k

आपके संशोधित कोड में, आप लौटाए गए मान को संदर्भ में डाल रहे हैं, जो तब अमान्य है।


5

उस संदर्भ में & का संदर्भ होता है - इसलिए फू एक इंट के बजाय एक इंट का संदर्भ देता है।

मुझे यकीन नहीं है कि अगर आपने अभी तक पॉइंटर्स के साथ काम किया है, लेकिन यह एक समान विचार है, तो आप वास्तव में फ़ंक्शन से मूल्य वापस नहीं कर रहे हैं - इसके बजाय आप स्मृति में स्थान खोजने के लिए आवश्यक जानकारी पास कर रहे हैं जहां int है

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

यदि आप सोच रहे हैं - आप सेगफॉल्ट होने का कारण यह है क्योंकि आप एक संख्यात्मक शाब्दिक '2' लौटा रहे हैं - तो यह सटीक त्रुटि है यदि आप एक कॉन्स्टेंट अंतर को परिभाषित करने और फिर इसे संशोधित करने का प्रयास करेंगे। मूल्य।

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


4

लिंक किए गए पृष्ठ पर उदाहरण कोड केवल एक डमी फ़ंक्शन घोषणा है। यह संकलित नहीं करता है, लेकिन यदि आपके पास कुछ फ़ंक्शन परिभाषित है, तो यह आम तौर पर काम करेगा। उदाहरण का अर्थ था "यदि आपके पास इस हस्ताक्षर के साथ एक फ़ंक्शन था, तो आप इसे इस तरह से उपयोग कर सकते हैं"।

आपके उदाहरण में, fooस्पष्ट रूप से हस्ताक्षर के आधार पर एक अंतराल वापस आ रहा है, लेकिन आप एक अंतराल लौटाते हैं जो एक अंतराल में परिवर्तित होता है। यह स्पष्ट रूप से विफल होने के लिए निर्धारित है। तुम यह कर सकते थे:

int& foo()
{
    static int x;
    return x;
}

और x का मान बदलकर सफल होगा, जब कह रहा है:

foo() = 10;

3

आपके पास जो फ़ंक्शन है, फू (), एक फ़ंक्शन है जो एक पूर्णांक के लिए एक संदर्भ देता है।

तो मान लीजिए कि मूल रूप से फू 5 लौट आया, और बाद में, आपके मुख्य कार्य में, आप कहते हैं foo() = 10; , फिर फू को प्रिंट करता है, यह 5 के बजाय 10 प्रिंट करेगा।

मुझे उम्मीद है कि इसका कोई अर्थ है :)

मैं प्रोग्रामिंग में भी नया हूँ। इस तरह के सवाल देखना दिलचस्प है जो आपको लगता है! :)

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