2010-11-03 3 views
13

में rvalues ​​करने के लिए गैर स्थिरांक संदर्भ पासिंग कोड की निम्न पंक्ति में:सी ++

bootrec_reset(File(path, size, off), blksize); 

प्रोटोटाइप के साथ एक समारोह कॉलिंग:

libcpfs/mkfs.cc:99:53: error: invalid initialization of non-const reference of type 'File&' from an rvalue of type 'File'

libcpfs/mkfs.cc:30:13: error: in passing argument 1 of 'void bootrec_reset(File&, ssize_t)'

:

static void bootrec_reset(File &file, ssize_t blksize); 

मैं यह त्रुटि प्राप्त

मुझे पता है कि आप गैर-कॉन्स संदर्भ (const &) को मानक के अनुसार रैल्यू में पारित नहीं कर सकते हैं। एमएसवीसी हालांकि आपको ऐसा करने की अनुमति देता है (this question देखें)। This question व्याख्या करने का प्रयास क्यों करता है लेकिन उत्तर को कोई अर्थ नहीं है क्योंकि वह शाब्दिक संदर्भों का उपयोग कर रहा है, जो एक कोने का मामला है और स्पष्ट रूप से अस्वीकृत होना चाहिए।

दिए गए उदाहरण यह देखने के लिए कि घटनाओं के निम्नलिखित क्रम हो जाएगा (के रूप में यह MSVC में करता है) स्पष्ट है में:

  1. File के निर्माता बुलाया जाएगा।
  2. File, और blksize का संदर्भ, ढेर पर धकेल दिया जाता है।
  3. bootrec_resetfile का उपयोग करता है।
  4. bootrec_reset से लौटने के बाद, अस्थायी File नष्ट हो गया है।

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

तो मेरी प्रश्न हैं:

  1. सी ++ मानक इस तरह से गैर स्थिरांक संदर्भ अनुमति न देने क्या सही ठहराते हैं?
  2. मैं इस कोड को अनुमति देने के लिए जीसीसी को कैसे मजबूर कर सकता हूं?
  3. क्या आगामी सी ++ 0x मानक इसे किसी भी रूप में बदलता है, या क्या नया मानक मुझे कुछ देता है जो यहां अधिक उचित है, उदाहरण के लिए सभी रावल संदर्भों के बारे में चिंतित हैं?

उत्तर

7

हां, तथ्य यह है कि सादा कार्य अस्थायी रूप से गैर-कॉन्स्ट संदर्भों को बाध्य नहीं कर सकते हैं - लेकिन विधियां - हमेशा मुझे खराब कर सकती हैं।

मान लीजिए आपके पास: TTBOMK तर्क कुछ इस तरह (this comp.lang.c++.moderated thread से प्राप्त) चला जाता है

void inc(long &x) { ++x; } 

void test() { 
    int y = 0; 
    inc(y); 
    std::cout << y; 
} 

आप inc() की long &x पैरामीटर एक अस्थायी long प्रतिलिपि y से बना करने के लिए बाध्य करने की अनुमति दी है, तो यह स्पष्ट रूप से कोड जो भी आप उम्मीद करते हैं वह नहीं करेगा - संकलक चुपचाप कोड उत्पन्न करेगा जो y अपरिवर्तित छोड़ देता है। जाहिर है यह शुरुआती सी ++ दिनों में बग का एक आम स्रोत था।

क्या मैंने सी ++ डिज़ाइन किया था, मेरी वरीयता गैर-कॉन्स संदर्भों को अस्थायी रूप से बांधने की अनुमति देनी होगी, लेकिन संदर्भों के लिए बाध्यकारी होने पर अंतराल से अस्थायी रूपांतरणों को प्रतिबंधित करने के लिए। लेकिन कौन जानता है, कि अच्छी तरह से कीड़े की एक अलग कर सकते हैं खोल दिया हो सकता है ...

+0

मुझे पता नहीं था कि संदर्भों के लिए बाध्यकारी होने पर अंतराल को अस्थायी रूपांतरित कर दिया गया था। यदि ऐसा है तो निर्णय समझ में आता है। * संपादित करें *: मैंने अभी इसका परीक्षण किया है और वे नहीं हैं? –

+0

@ मैट: नियम C++ 0x के साथ बदल गए। वह नियम परिवर्तन उदा। तर्क के रूप में 'std :: auto_ptr' गुजर रहा है। वैसे भी, जब कॉन्स्ट के संदर्भ में बाध्यकारी हो, और वास्तविक तर्क आवश्यक प्रकार (या व्युत्पन्न वर्ग) का नहीं है, तो एक अस्थायी रूप से पेश किया जाना चाहिए। चीयर्स, –

+0

@ मैट: आपने वास्तव में क्या परीक्षण किया? मेरा स्निपेट संकलित नहीं होना चाहिए क्योंकि सी ++ स्पष्ट रूप से एक अस्थायी (नवीनतम एमएसवीसी ++ और जी ++ इसे देखते हुए) को गैर-कॉन्स रेफरी बाध्यकारी रूप से अस्वीकार करता है; एक कॉन्स रेफरी को रेफरी बदलना निश्चित रूप से '++ x;' के कारण संकलन विफल हो जाएगा। –

2
  1. एक काफी मनमाना निर्णय है - temporaries करने के लिए गैर स्थिरांक संदर्भ स्मृति एक सदिश द्वारा आवंटित मुक्त करने के लिए अनुमति दी जाती है अस्थायी एक विधि कॉल का विषय है, उदाहरण के लिए (उदाहरण के लिए "स्वैप चाल" , std::vector<type>().swap(some_vector);)
  2. अस्थायी नाम देने का छोटा, मुझे नहीं लगता कि आप कर सकते हैं।
  3. जहां तक ​​मुझे पता है कि यह नियम सी ++ 0x में भी है (नियमित संदर्भों के लिए), लेकिन रावल संदर्भ विशेष रूप से मौजूद हैं ताकि आप अस्थायी संदर्भों को बाध्य कर सकें - इसलिए File && लेने के लिए bootrec_reset को बदलना कोड कानूनी बनाना चाहिए ।
+0

सदस्य-पहुंच मामले की तुलना वास्तव में अच्छा नहीं है। सदस्य-पहुंच ऑपरेटर रूपांतरणों पर विचार नहीं करता है। कॉन्स संदर्भों का बंधन करता है। –

+1

यह एक ऑर्थोगोनल मुद्दा है। यह दोनों का संयोजन है (अस्थायी रूपांतरण से प्राप्त किए गए अस्थायी लोगों को बाध्यकारी) जो वास्तव में अप्रत्याशित/आश्चर्यजनक व्यवहार का कारण बनता है; आप अनुमानतः अस्थायी रूप से संदर्भों की अनुमति दे सकते हैं लेकिन उस संदर्भ में किसी भी अंतर्निहित रूपांतरण की अनुमति नहीं देते हैं। –

+0

लेकिन गैर-कॉन्स्ट संदर्भों को बाध्य करते समय निहित रूपांतरणों की अनुमति है। आप गंभीरता से इसे लेने का सुझाव नहीं दे रहे हैं, है ना? फिर हम ऐसी चीजें रखने के लिए वापस आ गए हैं जो संदर्भों से बंधे हैं, न कि गैर-कॉन्स्टेंस संदर्भों के लिए, जहां भाषा अभी है। –

1

कृपया ध्यान दें कि सी ++ 0x "जिबर्बिश" को कॉल करना आपकी कोडिंग क्षमता या भाषा को समझने की इच्छा का एक बहुत ही अनुकूल चित्र प्रस्तुत नहीं कर रहा है।

1) वास्तव में इतना मनमाना नहीं है। आर-वैल्यू से जुड़ने के लिए गैर-कॉन्स संदर्भों को अनुमति देने से बेहद भ्रमित कोड होता है। मैंने हाल ही में एमएसवीसी के खिलाफ एक बग दायर किया जो इस से संबंधित है, जहां गैर-मानक व्यवहार ने मानक-अनुपालन कोड को संकलित करने और/या एक भयानक व्यवहार के साथ संकलित करने में असफल होने का असर डाला।

आपके मामले में, पर विचार करें:

#include <iostream> 

template<typename T> 
void func(T& t) 
{ 
    int& r = t; 
    ++r; 
} 

int main(void) 
{ 
    int i = 4; 
    long n = 5; 
    const int& r = n; 

    const int ci = 6; 
    const long cn = 7; 

    //int& r1 = ci; 
    //int& r2 = cn; 

    func(i); 
    //func(n); 

    std::cout << r << std::endl; 
} 

टिप्पणी की लाइनों में से कौन सा संकलित करने के लिए करना चाहते हैं? क्या आप ऐसा करने के लिए func(i) अपनी तर्क और func(n) बदलने के लिए चाहते हैं?

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

{ 
    File ftemp(path, size, off); 
    bootrec_reset(ftemp, blksize); 
} 

3) हां, आप इस परिदृश्य में सी ++ 0x आर-मान संदर्भों का उपयोग कर सकते हैं।

+0

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

+0

@j_random_hacker: मैं बस एक और जटिल उदाहरण पर काम कर रहा था। लेकिन मैं आपके (ए) को समझ नहीं पा रहा हूं, आर-मानों में स्थिरता नहीं है। आप कॉन्स ऑब्जेक्ट्स, अवधि से किसी स्वचालित रूपांतरण को रोकना चाहते हैं? –

+0

@बेन: ठीक है मेरी समझ थोड़ा कमजोर है, लेकिन मुझे लगता है कि रावलों में स्थिरता हो सकती है (या नहीं) स्थिरता - हालांकि अंतर केवल वर्ग प्रकार की वस्तुओं के लिए महत्वपूर्ण है (यदि रावल्यू कॉन्स है तो केवल कॉन्स विधियों को ही बुलाया जा सकता है यह)। और हां, मैं प्रस्तावित कर रहा हूं कि कोई स्वचालित रूपांतरण * जो किसी अस्थिर वस्तु से अस्थायी * उत्पन्न नहीं करेगा - क्या आपको शायद इस से उत्पन्न अनपेक्षित परिणाम दिखाई दे? –

6
  • "सी ++ इस तरह से मानक अनुमति न देने गैर स्थिरांक संदर्भ क्या सही ठहराते हैं?"

विपरीत सम्मेलन के साथ व्यावहारिक अनुभव, जो मूल रूप से चीजें कैसे काम करती थीं। सी ++ एक विकसित भाषा की एक बड़ी डिग्री है, एक डिजाइन नहीं है। बड़े पैमाने पर, जो नियम अभी भी हैं वे काम करने के लिए निकले हैं (हालांकि 1 99 8 के मानकीकरण के साथ कुछ बड़े अपवाद हैं, उदाहरण के लिए कुख्यात export, जहां समिति ने मौजूदा अभ्यास को मानकीकृत करने के बजाय आविष्कार किया)।

बाध्यकारी नियम के लिए किसी को न केवल सी ++ में अनुभव था, बल्कि फोरट्रान जैसी अन्य भाषाओं के साथ भी इसी तरह का अनुभव था।

जैसा कि @j_random_hacker उनके उत्तर में नोट करता है (जैसा कि मैंने लिखा था, यह 0 रन बना था, यह दर्शाता है कि एसओ में स्कोरिंग वास्तव में गुणवत्ता के उपाय के रूप में काम नहीं करती है), सबसे गंभीर समस्याओं को निहित रूपांतरणों के साथ करना है और अधिभार संकल्प।

  • "मैं इस कोड को अनुमति देने के लिए जीसीसी को कैसे मजबूर कर सकता हूं?"

आप नहीं कर सकते।

बजाय

...

bootrec_reset(File(path, size, off), blksize); 

... लिखने ...

File f(path, size, off); 
bootrec_reset(f, blksize); 

या bootrec_reset का एक उपयुक्त अधिभार परिभाषित करते हैं। या, यदि "चालाक" कोड अपील करता है, तो आप सिद्धांत रूप से bootrec_reset(tempref(File(path, size, off)), blksize); लिख सकते हैं, जहां आप tempref को अपने तर्क संदर्भ को उचित रूप से कॉन्स्ट-कास्ट करने के लिए परिभाषित करते हैं। लेकिन भले ही यह एक तकनीकी समाधान है, नहीं।

  • "फिर भी आगामी C++ 0x मानक इस परिवर्तन करता है, या वहाँ कुछ है नए मानक मुझे देता है कि अधिक उपयुक्त यहाँ, उदाहरण के लिए rvalue संदर्भों के बारे में वह सब jibberish है?"

नहीं, कुछ भी नहीं जो दिए गए कोड के लिए चीजें बदलता है।

यदि आप फिर से लिखना चाहते हैं, तो आप उदाहरण का उपयोग कर सकते हैं। सी ++ 0x रावल संदर्भ, या ऊपर दिखाए गए सी ++ 98 वर्कअराउंड।

चीयर्स & hth।,

6

Does the upcoming C++0x standard change this in anyway, or is there something the new standard gives me that is more appropriate here, for example all that jibberish about rvalue references?

हां। चूंकि हर नाम एक lvalue है, यह लगभग किसी भी अभिव्यक्ति के इलाज के लिए तुच्छ के रूप में अगर यह एक lvalue था:

template <typename T> 
T& as_lvalue(T&& x) 
{ 
    return x; 
} 

// ... 

bootrec_reset(as_lvalue(File(path, size, off)), blksize); 
1

वैकल्पिक रूप से, बस अधिभार।

static void bootrec_reset(File &&file, ssize_t blksize) { 
    return bootrec_reset(file, blksize); 
} 

यह सबसे आसान समाधान है।

0

How can I force GCC to permit this code?

आप फ़ाइल की परिभाषा के मालिक हैं तो आप इसी प्रकार के गुर खेलने की कोशिश कर सकते हैं:

class File /* ... */ { 
public: 
    File* operator&() { return this; } 
/* ... */ 
}; 
/* ... */ 
bootrec_reset(*&File(path, size, off), blksize); 

यह C++ 98 मोड मेरे लिए संकलित करता है।

Does the upcoming C++0x standard change this in anyway, or is there something the new standard gives me that is more appropriate here, for example all that jibberish about rvalue references?

स्पष्ट रूप से यदि संभव हो तो यह जाने का तरीका।