क्या C ++ संदर्भ चर बुराई को वापस करने का अभ्यास है?


341

यह थोड़ा व्यक्तिपरक है जो मुझे लगता है; मुझे यकीन नहीं है कि अगर राय एकमत होगी (मैंने बहुत सारे कोड स्निपेट देखे हैं जहां संदर्भ वापस आ गए हैं)।

इस प्रश्न की ओर एक टिप्पणी के अनुसार , मैंने केवल संदर्भों को आरम्भ करने के बारे में पूछा था, एक संदर्भ को वापस करने से बुराई हो सकती है क्योंकि, [जैसा कि मैं समझता हूं] इसे हटाने से चूकना आसान हो जाता है, जिससे मेमोरी लीक हो सकती है।

यह मुझे चिंतित करता है, जैसा कि मैंने उदाहरणों का पालन किया है (जब तक कि मैं चीजों की कल्पना नहीं कर रहा हूं) और कुछ उचित स्थानों पर ऐसा किया है ... क्या मुझे गलत समझा गया है? क्या यह बुराई है? यदि हां, तो कैसे बुराई?

मुझे लगता है कि बिंदुओं और संदर्भों के मेरे मिश्रित बैग के कारण, इस तथ्य के साथ संयुक्त हूं कि मैं सी ++ के लिए नया हूं, और कुल मिलाकर भ्रम है कि कब, क्या उपयोग करना है, मेरे अनुप्रयोगों को स्मृति रिसाव नरक होना चाहिए ...

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


यह बुरा नहीं है अगर आप गेट्टर जैसे कार्य / तरीके लिख रहे हैं।
जॉन जेड। ली

जवाबों:


411

सामान्य तौर पर, एक संदर्भ लौटना पूरी तरह से सामान्य है और हर समय होता है।

यदि तुम्हारा मतलब:

int& getInt() {
    int i;
    return i;  // DON'T DO THIS.
}

वह सब प्रकार की बुराई है। स्टैक-आबंटित iचला जाएगा और आप कुछ भी नहीं करने की बात कर रहे हैं। यह भी बुराई है:

int& getInt() {
    int* i = new int;
    return *i;  // DON'T DO THIS.
}

क्योंकि अब ग्राहक को अंततः अजीब करना पड़ता है:

int& myInt = getInt(); // note the &, we cannot lose this reference!
delete &myInt;         // must delete...totally weird and  evil

int oops = getInt(); 
delete &oops; // undefined behavior, we're wrongly deleting a copy, not the original

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

यदि आप कुछ ऐसा आवंटित करना चाहते हैं जो फ़ंक्शन के दायरे से परे रहता है, तो स्मार्ट पॉइंटर (या सामान्य रूप से, कंटेनर) का उपयोग करें:

std::unique_ptr<int> getInt() {
    return std::make_unique<int>(0);
}

और अब ग्राहक एक स्मार्ट पॉइंटर को स्टोर करता है:

std::unique_ptr<int> x = getInt();

उन चीजों तक पहुंचने के लिए संदर्भ भी ठीक है, जहां आप जानते हैं कि जीवनकाल को उच्च-स्तर पर खुला रखा जा रहा है, जैसे:

struct immutableint {
    immutableint(int i) : i_(i) {}

    const int& get() const { return i_; }
private:
    int i_;
};

यहाँ हम जानते हैं कि किसी संदर्भ को वापस करना ठीक है i_क्योंकि जो कुछ भी हमें कॉल कर रहा है वह जीवन भर के वर्ग के उदाहरण का प्रबंधन करता है, इसलिए i_कम से कम वह लंबे समय तक जीवित रहेगा।

और हां, इसमें कुछ गलत नहीं है:

int getInt() {
   return 0;
}

यदि आजीवन कॉल करने वाले को छोड़ दिया जाना चाहिए, और आप केवल मूल्य की गणना कर रहे हैं।

सारांश: यदि कॉल के बाद ऑब्जेक्ट का जीवनकाल समाप्त नहीं होगा, तो संदर्भ वापस करना ठीक है।


21
ये सभी बुरे उदाहरण हैं। उचित उपयोग का सबसे अच्छा उदाहरण है जब आप किसी ऑब्जेक्ट के संदर्भ में लौट रहे हैं, जो में पारित किया गया था। अला ऑपरेटर <<
Arelius

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

12
अनुमोदन को संपादित करें: यदि आप इसकी शुद्धता के लिए व्रत नहीं कर सकते हैं तो संपादन को मंजूरी न दें। मैंने गलत संपादन रोलबैक किया है।
GMANNICKG

7
पश्चाताप के लिए, और किसी भी नए प्रोग्रामर के लिए इस पर मंथन करने के लिए, न लिखेंreturn new int
को ऑर्बिट

3
पश्चाताप के लिए, और इस पर किसी भी नए प्रोग्रामर के लिए, केवल समारोह से टी वापस लौटाएं। आरवीओ हर चीज का ख्याल रखेगा।
जूता

64

नहीं, नहीं, नहीं, हजार बार नहीं।

बुराई क्या है एक गतिशील रूप से आवंटित वस्तु का संदर्भ बना रही है और मूल सूचक को खो रही है। जब आप newएक वस्तु आप एक दायित्व मान एक गारंटी है delete

लेकिन एक नज़र है, उदाहरण के लिए operator<<: कि एक संदर्भ लौटाना चाहिए , या

cout << "foo" << "bar" << "bletch" << endl ;

काम नहीं करेगा।


23
मैंने यह अस्वीकार कर दिया क्योंकि यह न तो प्रश्न का उत्तर देता है (जिसमें ओपी ने स्पष्ट किया है कि वह विलोपन की आवश्यकता को जानता है) और न ही वैध भय को संबोधित करता है कि एक फ्रीस्टोर ऑब्जेक्ट के संदर्भ में लौटने से भ्रम पैदा हो सकता है। आह।

4
संदर्भ वस्तु वापस करने की प्रथा बुराई नहीं है। एर्गो नं। जिस भय को वह व्यक्त करता है वह एक सही भय है, जैसा कि मैं दूसरे ग्राफ में इंगित करता हूं।
चार्ली मार्टिन

आपने वास्तव में नहीं किया। लेकिन यह मेरे समय के लायक नहीं है।

2
इरिंबिलंजा @ के बारे में "नहीं" -s मुझे परवाह नहीं है। लेकिन इस पोस्ट में एक महत्वपूर्ण जानकारी दी गई है जो GMan से गायब थी।
Kobor42

48

आपको एक मौजूदा ऑब्जेक्ट का संदर्भ वापस करना चाहिए जो तुरंत दूर नहीं हो रहा है, और जहां आप स्वामित्व के किसी भी हस्तांतरण का इरादा नहीं रखते हैं।

स्थानीय चर या कुछ ऐसे संदर्भ का संदर्भ कभी न दें, क्योंकि यह संदर्भित नहीं होगा।

आप फ़ंक्शन के कुछ स्वतंत्र संदर्भ का संदर्भ दे सकते हैं, जिसे हटाने की जिम्मेदारी लेने के लिए आप कॉलिंग फ़ंक्शन की अपेक्षा नहीं करते हैं। यह विशिष्ट operator[]कार्य के लिए मामला है।

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


1
उत्कृष्ट उत्तर लेकिन "आप एक अस्थायी संदर्भ के रूप में लौट सकते हैं।" निम्न कोड संकलित करेगा, लेकिन शायद दुर्घटनाग्रस्त हो जाएगा क्योंकि अस्थायी रिटर्न स्टेटमेंट के अंत में नष्ट हो जाता है: "int const & f () {return 42;} void main () {int const & r = f (); ++ r;}; "
j_random_hacker

@j_random_hacker: सी ++ में अस्थायी लोगों के संदर्भ के लिए कुछ अजीब नियम हैं, जहां अस्थायी जीवनकाल बढ़ाया जा सकता है। मुझे खेद है कि मुझे यह अच्छी तरह से समझ में नहीं आ रहा है कि क्या यह आपके मामले को कवर करता है।
मार्क रैनसम

3
@ मर्क: हां, इसमें कुछ अजीब नियम हैं। एक अस्थायी जीवनकाल केवल एक कॉन्स्ट रेफरेंस (जो कि क्लास का सदस्य नहीं है) को इसके साथ जोड़कर बढ़ाया जा सकता है; यह तब तक रहता है जब तक कि रेफ दायरे से बाहर नहीं चला जाता है। अफसोस की बात है कि एक कास्ट रेफरी वापस नहीं आया है। हालांकि मूल्य द्वारा एक अस्थायी रिटर्निंग सुरक्षित है।
j_random_hacker 3

C ++ मानक, 12.2, पैरा 5 देखें। जड़ी- बूटियों के भंडार में हर्ब सटर के आवारा गुरु को भी देखें ।wordpress.com / 2008 / 01 / 01/…
डेविड थॉर्नले

4
@ दाऊद: जब फ़ंक्शन द्वारा दिया गया प्रकार "टी स्थिरांक और" है, क्या वास्तव में ऐसा होता है कि वापसी कथन है परोक्ष धर्मान्तरित टाइप "टी स्थिरांक और" प्रति 6.6.3.2 (एक कानूनी रूपांतरण लेकिन एक के रूप में करने के लिए, अस्थायी, प्रकार टी की है जो जो जीवनकाल का विस्तार नहीं करता है), और फिर कॉलिंग कोड फ़ंक्शन के परिणाम के साथ "टी कॉन्स्ट एंड" के प्रकार को शुरू करता है, टाइप "टी कॉन्स्ट एंड" का भी - फिर से, एक कानूनी लेकिन गैर-जीवनकाल-विस्तारित प्रक्रिया। अंतिम परिणाम: जीवनकाल का कोई विस्तार नहीं, और बहुत भ्रम। :(
j_random_hacker

26

मुझे लगता है कि उत्तर संतोषजनक नहीं हैं इसलिए मैं अपने दो सेंट जोड़ूंगा।

आइए निम्नलिखित मामलों का विश्लेषण करें:

त्रुटिपूर्ण उपयोग

int& getInt()
{
    int x = 4;
    return x;
}

यह स्पष्ट रूप से त्रुटि है

int& x = getInt(); // will refer to garbage

स्थैतिक चर के साथ उपयोग

int& getInt()
{
   static int x = 4;
   return x;
}

यह सही है, क्योंकि स्थिर चर एक कार्यक्रम के जीवन भर में मौजूद हैं।

int& x = getInt(); // valid reference, x = 4

सिंगलटन पैटर्न को लागू करते समय यह भी काफी सामान्य है

Class Singleton
{
    public:
        static Singleton& instance()
        {
            static Singleton instance;
            return instance;
        };

        void printHello()
        {
             printf("Hello");
        };

}

उपयोग:

 Singleton& my_sing = Singleton::instance(); // Valid Singleton instance
 my_sing.printHello();  // "Hello"

ऑपरेटर्स

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

T & operator*();

निम्नलिखित में इस्तेमाल किया जा सकता है

std::vector<int> x = {1, 2, 3}; // create vector with 3 elements
std::vector<int>::iterator iter = x.begin(); // iterator points to first element (1)
*iter = 2; // modify first element, x = {2, 2, 3} now

आंतरिक डेटा तक त्वरित पहुंच

ऐसे समय होते हैं जब आंतरिक डेटा तक त्वरित पहुंच के लिए इस्तेमाल किया जा सकता है

Class Container
{
    private:
        std::vector<int> m_data;

    public:
        std::vector<int>& data()
        {
             return m_data;
        }
}

उपयोग के साथ:

Container cont;
cont.data().push_back(1); // appends element to std::vector<int>
cont.data()[0] // 1

फिर भी, यह इस तरह के रूप में नुकसान हो सकता है:

Container* cont = new Container;
std::vector<int>& cont_data = cont->data();
cont_data.push_back(1);
delete cont; // This is bad, because we still have a dangling reference to its internal data!
cont_data[0]; // dangling reference!

एक स्थिर चर के संदर्भ में लौटने से अवांछित व्यवहार हो सकता है। उदाहरण के लिए एक बहु ऑपरेटर पर विचार करें जो एक स्थैतिक सदस्य का संदर्भ देता है तो निम्न परिणाम हमेशा trueIf((a*b) == (c*d))
सामने आएगा

Container::data()के कार्यान्वयन को पढ़ना चाहिएreturn m_data;
Xeaz

यह बहुत मददगार था, धन्यवाद! @Xeaz कि हालांकि एपेंड कॉल के साथ मुद्दों का कारण नहीं होगा?
एंड्रयू

@SebTu आप भी ऐसा क्यों करना चाहेंगे?
थिरुहंटर

@ और नहीं, यह एक वाक्यविन्यास शब्द था। यदि आप, उदाहरण के लिए, एक पॉइंटर प्रकार लौटाया है, तो आप पॉइंटर बनाने और वापस करने के लिए संदर्भ पते का उपयोग करेंगे।
थिरुहंटर

14

यह बुराई नहीं है। C ++ की कई चीजों की तरह, अगर इसका सही तरीके से उपयोग किया जाए तो अच्छा है, लेकिन इसके उपयोग के समय आपको कई नुकसान होने चाहिए (जैसे किसी स्थानीय चर का संदर्भ देना)।

अच्छी चीजें हैं जो इसके साथ हासिल की जा सकती हैं (जैसे नक्शा [नाम] = "हैलो वर्ल्ड")


1
मैं बस उत्सुक हूँ, क्या अच्छा है map[name] = "hello world"?
अशुभनाम अष्टक २०'११ बजे us:

5
@wrongusername सिंटैक्स सहज है। कभी HashMap<String,Integer>जावा में संग्रहीत मूल्य की गिनती बढ़ाने की कोशिश की ? : पी
मेहरदाद अफशरी

हाहा, अभी तक नहीं, लेकिन
हाशप के

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

10

"एक संदर्भ को वापस करना बुरा है क्योंकि, जैसा कि [जैसा कि मैं समझता हूं] यह इसे हटाने से चूकना आसान बनाता है"

सच नहीं। एक संदर्भ लौटाने से शब्दार्थ का स्वामित्व नहीं होता है। यह है, सिर्फ इसलिए कि आप ऐसा करते हैं:

Value& v = thing->getTheValue();

... इसका मतलब यह नहीं है कि अब आप v द्वारा संदर्भित मेमोरी के मालिक हैं;

हालाँकि, यह भयानक कोड है:

int& getTheValue()
{
   return *new int;
}

यदि आप ऐसा कुछ कर रहे हैं क्योंकि "आपको उस उदाहरण पर एक पॉइंटर की आवश्यकता नहीं है" तो: 1) यदि आपको एक संदर्भ की आवश्यकता है, तो पॉइंटर को केवल हटा दें, और 2) आपको अंततः पॉइंटर की आवश्यकता होगी, क्योंकि आपको एक मैच करना होगा हटाने के साथ नया, और आपको कॉल हटाने के लिए पॉइंटर की आवश्यकता है।


7

दो मामले हैं:

  • कॉन्स्ट रेफरेंस - अच्छा विचार, कभी-कभी, विशेष रूप से भारी वस्तुओं या प्रॉक्सी कक्षाओं, संकलक अनुकूलन के लिए

  • नॉन-कॉन्स्टिट रेफ़र -बैड विचार, कभी-कभी, इनकैप्सुलेशन को तोड़ता है

दोनों एक ही मुद्दे को साझा करते हैं - संभावित रूप से नष्ट वस्तु की ओर इशारा कर सकते हैं ...

मैं कई स्थितियों के लिए स्मार्ट पॉइंटर्स का उपयोग करने की सलाह दूंगा जहां आपको संदर्भ / पॉइंटर वापस करने की आवश्यकता होती है।

इसके अलावा, निम्नलिखित पर ध्यान दें:

एक औपचारिक नियम है - C ++ Standard (यदि आप रुचि रखते हैं तो खंड 13.3.3.1.4) बताता है कि एक अस्थायी केवल एक कॉन्स्ट रेफरेंस के लिए बाध्य हो सकता है - यदि आप एक नॉन-कॉस्ट रेफरेंस का उपयोग करने की कोशिश करते हैं तो कंपाइलर को इसे फ्लैग करना चाहिए एक त्रुटि।


1
गैर-कॉन्स्टेंट रेफरी जरूरी नहीं कि एनकैप्सुलेशन को तोड़ता है। वेक्टर पर विचार करें: ऑपरेटर []

यह एक बहुत ही खास मामला है ... इसीलिए मैंने कभी-कभी कहा, हालाँकि मुझे वास्तव में दावा करना चाहिए :)

तो, आप कह रहे हैं कि सामान्य सबस्क्रिप्ट ऑपरेटर एक आवश्यक बुराई को लागू कर रहा है? मैं इससे न तो असहमत हूँ और न ही सहमत हूँ; जैसा कि मैं समझदार नहीं हूं।
निक बोल्टन

मैं ऐसा नहीं कहता, लेकिन इसका गलत इस्तेमाल होने पर बुराई हो सकती है :))) वेक्टर :: पर जब भी संभव हो इस्तेमाल किया जाना चाहिए ....

एह? वेक्टर :: पर भी एक नॉनकॉस्ट रेफरी देता है।

4

न केवल यह बुराई नहीं है, यह कभी-कभी आवश्यक है। उदाहरण के लिए, एक संदर्भ वापसी मूल्य का उपयोग किए बिना, std :: वेक्टर के ऑपरेटर को लागू करना असंभव होगा।


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

अजीब तरह से पर्याप्त है, आप operator[]एक संदर्भ के उपयोग के बिना एक कंटेनर के लिए लागू कर सकते हैं ... और std::vector<bool>करता है। (और इस प्रक्रिया में एक असली गड़बड़ पैदा करता है)
बेन वोइग्ट

@BenVoigt एमएमएम, क्यों एक गड़बड़ है? प्रॉक्सी लौटना भी जटिल भंडारण वाले कंटेनरों के लिए एक वैध परिदृश्य है जो सीधे बाहरी प्रकारों (जैसे ::std::vector<bool>आपने उल्लेख किया है) पर मैप नहीं करता है ।
सेर्गेई.विक्सियोटिकैक्सिस. इवानोव

1
@ सेर्गेई.विक्सियोटिकैक्सिस इवानोव: गड़बड़ यह है कि std::vector<T>टेम्पलेट कोड का उपयोग करना टूट गया है, यदि Tहो सकता है bool, क्योंकि std::vector<bool>अन्य तात्कालिकता से बहुत अलग व्यवहार है। यह उपयोगी है, लेकिन इसे अपना नाम दिया जाना चाहिए था न कि विशेषज्ञता का std::vector
बेन वोइग्ट

@BenVoight मैं एक विशेषज्ञता को "वास्तव में विशेष" बनाने के अजीब निर्णय के बारे में बात पर सहमत हूं, लेकिन मुझे लगा कि आपकी मूल टिप्पणी का तात्पर्य है कि प्रॉक्सी वापस करना सामान्य रूप से अजीब है।
सेर्गेई.विक्सियोटिकैक्सिस। इवानोव

2

स्वीकृत उत्तर के अलावा:

struct immutableint {
    immutableint(int i) : i_(i) {}

    const int& get() const { return i_; }
private:
    int i_;
};

मेरा तर्क है कि यह उदाहरण ठीक नहीं है और यदि संभव हो तो इसे टाला जाना चाहिए। क्यों? झूलते संदर्भ के साथ अंत करना बहुत आसान है ।

एक उदाहरण के साथ बिंदु को समझने के लिए:

struct Foo
{
    Foo(int i = 42) : boo_(i) {}
    immutableint boo()
    {
        return boo_;
    }  
private:
    immutableint boo_;
};

खतरे क्षेत्र में प्रवेश:

Foo foo;
const int& dangling = foo.boo().get(); // dangling reference!

1

रिटर्न रेफरेंस का उपयोग आमतौर पर C ++ में ऑपरेटर द्वारा बड़े ऑब्जेक्ट के लिए ओवरलोडिंग में किया जाता है, क्योंकि वैल्यू की आवश्यकता कॉपी ऑपरेशन को वापस करने में होती है। (पेरेटर ओवरलोडिंग में, हम आमतौर पर रिटर्न वैल्यू के रूप में पॉइंटर का उपयोग नहीं करते हैं)

लेकिन वापसी के संदर्भ में स्मृति आवंटन समस्या हो सकती है। क्योंकि परिणाम का एक संदर्भ फ़ंक्शन से वापसी मान के संदर्भ के रूप में पारित किया जाएगा, वापसी मान एक स्वचालित चर नहीं हो सकता है।

यदि आप रेफ़रिंग रिटर्न का उपयोग करना चाहते हैं, तो आप स्टैटिक ऑब्जेक्ट के बफर का उपयोग कर सकते हैं। उदाहरण के लिए

const max_tmp=5; 
Obj& get_tmp()
{
 static int buf=0;
 static Obj Buf[max_tmp];
  if(buf==max_tmp) buf=0;
  return Buf[buf++];
}
Obj& operator+(const Obj& o1, const Obj& o1)
{
 Obj& res=get_tmp();
 // +operation
  return res;
 }

इस तरह, आप सुरक्षित रूप से रिटर्निंग संदर्भ का उपयोग कर सकते हैं।

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


0

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


0

सबसे अच्छी बात यह है कि ऑब्जेक्ट बनाएं और इसे फ़ंक्शन / संदर्भ पैरामीटर के रूप में पास करें जो इस चर को आवंटित करता है।

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


-1
    Class Set {
    int *ptr;
    int size;

    public: 
    Set(){
     size =0;
         }

     Set(int size) {
      this->size = size;
      ptr = new int [size];
     }

    int& getPtr(int i) {
     return ptr[i];  // bad practice 
     }
  };

getPtr फ़ंक्शन विलोपन या एक अशक्त वस्तु के बाद गतिशील मेमोरी तक पहुंच सकता है। जो बैड एक्सेस एक्सेप्शन का कारण बन सकता है। इसके बजाय गेट्टर और सेटर को लागू किया जाना चाहिए और लौटने से पहले सत्यापित किया जाना चाहिए।


-2

लवल्यू के रूप में कार्य (उर्फ, गैर-कास्ट संदर्भों की वापसी) को C ++ से हटा दिया जाना चाहिए। यह बहुत अचूक है। स्कॉट मेयर्स इस व्यवहार के साथ एक मिनट () चाहते थे।

min(a,b) = 0;  // What???

जो वास्तव में एक सुधार नहीं है

setmin (a, b, 0);

उत्तरार्द्ध भी अधिक समझ में आता है।

मुझे पता है कि सी + + शैली धाराओं के लिए लवल्यू के रूप में कार्य महत्वपूर्ण है, लेकिन यह इंगित करने योग्य है कि सी ++ शैली की धाराएं भयानक हैं। मैं अकेला ऐसा नहीं हूं जो यह सोचता है ... जैसा कि मुझे याद है कि अलेक्जेंड्रेस्कु के पास बेहतर करने के तरीके पर एक बड़ा लेख था, और मेरा मानना ​​है कि बढ़ावा ने एक बेहतर प्रकार I / O विधि बनाने का भी प्रयास किया है।


2
यकीन है कि यह खतरनाक है, और बेहतर संकलक त्रुटि जांच होनी चाहिए, लेकिन इसके बिना कुछ उपयोगी निर्माण नहीं किया जा सकता है, उदाहरण के लिए ऑपरेटर [] () std :: map में।
j_random_hacker

2
गैर-कास्ट संदर्भों को वापस करना वास्तव में अविश्वसनीय रूप से उपयोगी है। vector::operator[]उदाहरण के लिए। आप बल्कि लिखेंगे v.setAt(i, x)या v[i] = x? बाद वाला एफएआर श्रेष्ठ है।
माइल राउत

1
@ माइल्सआउट मैं v.setAt(i, x)किसी भी समय के लिए जाऊँगा । यह एफएआर श्रेष्ठ है।
10

-2

मैं एक वास्तविक समस्या में भाग गया जहाँ यह वास्तव में बुराई थी। अनिवार्य रूप से एक डेवलपर ने एक वेक्टर में एक वस्तु के संदर्भ को वापस कर दिया। वह खराब था!!!

पूरा विवरण मैंने जनूरी में लिखा है: http://developer-resource.blogspot.com/2009/01/pros-and-cons-of-returing-references.html


2
यदि आपको कॉलिंग कोड में मूल मूल्य को संशोधित करने की आवश्यकता है, तो आपको एक रेफरी वापस करने की आवश्यकता है। और यह वास्तव में वेक्टर से पुनरावृत्ति करने वाले से अधिक खतरनाक और कोई कम खतरनाक नहीं है - दोनों को अमान्य कर दिया जाता है यदि तत्वों को वेक्टर से जोड़ा जाता है या हटाया जाता है।
j_random_hacker

वह विशेष समस्या एक वेक्टर तत्व के संदर्भ को रखने के कारण हुई थी, और फिर उस वेक्टर को इस तरह से संशोधित किया गया था जो संदर्भ को अमान्य करता है: पृष्ठ 153, "C ++ मानक पुस्तकालय: एक ट्यूटोरियल और संदर्भ" का खंड 6.2 - जोसटिस, पढ़ता है: "सम्मिलित करता है" या हटाने वाले तत्व संदर्भों, पॉइंटर्स और पुनरावृत्तियों को अमान्य करते हैं, जो निम्न तत्वों को संदर्भित करते हैं। यदि सम्मिलन वसूली का कारण बनता है, तो यह सभी संदर्भों, पुनरावृत्तियों, और संकेत को अमान्य करता है "
ट्रेंट

-15

भयानक कोड के बारे में:

int& getTheValue()
{
   return *new int;
}

तो, वास्तव में, मेमोरी पॉइंटर वापसी के बाद खो गया। लेकिन अगर आप share_ptr का उपयोग करते हैं जैसे:

int& getTheValue()
{
   std::shared_ptr<int> p(new int);
   return *p->get();
}

स्मृति वापसी के बाद नहीं खो गई और असाइनमेंट के बाद मुक्त हो जाएगी।


12
यह खो गया है क्योंकि साझा सूचक दायरे से बाहर हो जाता है और पूर्णांक को मुक्त करता है।

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