कब्ज के संदर्भ में क्या कोई फायदा है?


90

मुझे लगता है कि नहीं, लेकिन मैं पुष्टि करना चाहता हूं। क्या इसका कोई उपयोग है const Foo&&, जहां Fooएक वर्ग प्रकार है?


2
इस वीडियो में, एसटीएल कहता है कि const&&यह बहुत महत्वपूर्ण है, हालांकि वह यह नहीं कहता कि क्यों: youtube.com/watch?v=JhgWFYfdIho#t=54m20s
हारून मैकडैड

जवाबों:


79

वे कभी-कभी उपयोगी होते हैं। C ++ 0x का मसौदा स्वयं उन्हें कुछ स्थानों पर उपयोग करता है, उदाहरण के लिए:

template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;

उपर्युक्त दो अधिभार यह सुनिश्चित करते हैं कि अन्य ref(T&)और cref(const T&)फ़ंक्शंस प्रतिद्वंद्वियों के लिए बाध्य नहीं हैं (जो अन्यथा संभव होगा)।

अपडेट करें

मैंने अभी आधिकारिक मानक N3290 की जांच की है , जो दुर्भाग्य से सार्वजनिक रूप से उपलब्ध नहीं है, और इसमें 20.8 फ़ंक्शन ऑब्जेक्ट्स [function.objects] / P2 हैं:

template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;

तब मैंने सबसे हालिया पोस्ट-सी ++ 11 ड्राफ्ट की जांच की, जो सार्वजनिक रूप से उपलब्ध है, N3485 , और 20.8 फ़ंक्शन ऑब्जेक्ट्स [function.objects] / P2 में यह अभी भी कहता है:

template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;

Cppreference को देखते हुए ऐसा प्रतीत होता है कि अब ऐसा नहीं है। कोई विचार क्यों? किसी अन्य स्थान const T&&का उपयोग किया जाता है?
पब्बी

60
आपने तीन बार अपने उत्तर में एक ही कोड क्यों शामिल किया? मैंने बहुत लंबे समय तक अंतर खोजने की कोशिश की।
टाइप 1232

9
@ टाइप 1232: ऐसा प्रतीत होता है कि मैंने जवाब देने के लगभग 2 साल बाद अपडेट किया, टिप्पणियों में चिंताओं के कारण कि संदर्भित फ़ंक्शन अब दिखाई नहीं देते हैं। मैंने N3290 से कॉपी / पेस्ट किया, और तत्कालीन नवीनतम ड्राफ्ट N3485 से यह दिखाने के लिए कि फ़ंक्शंस अभी भी दिखाई दिए हैं। उस समय मेरे दिमाग में कॉपी / पेस्ट का उपयोग करना, यह सुनिश्चित करने का सबसे अच्छा तरीका था कि मेरी तुलना में अधिक आंखें इस बात की पुष्टि कर सकती थीं कि मैं इन हस्ताक्षरों में कुछ मामूली बदलाव को नजरअंदाज नहीं कर रहा था।
हावर्ड हेन्ट जूल 15'13

1
@kevinarpe: "अन्य अधिभार" (यहां नहीं दिखाया गया है, लेकिन मानक में) अंतराल संदर्भ लेते हैं, और हटाए नहीं जाते हैं। यहां दिखाए गए ओवरलोड, प्रतिद्वंद्वियों के लिए एक बेहतर मैच हैं, जो ओवरलोड्स हैं जो लैवल्यू संदर्भ लेते हैं। तो प्रतिद्वंद्विता तर्क यहाँ दिखाए गए अधिभार को बांधते हैं, और फिर एक संकलन समय त्रुटि का कारण बनते हैं क्योंकि ये अधिभार हटा दिए जाते हैं।
हावर्ड हिनान्ट

1
const T&&प्रपत्र के स्पष्ट टेम्पलेट आर्गन्स का उपयोग करके किसी को मूर्खतापूर्ण तरीके से रोकता है ref<const A&>(...)। यह बहुत मजबूत तर्क नहीं है, लेकिन const T&&अधिक लागत T&&बहुत कम है।
हावर्ड हिनांत

6

पाने का शब्दार्थ कॉन्स्टेबल रैवल्यू रेफरेंस (और नहीं के लिए=delete):

  • हम lvalues ​​के लिए ऑपरेशन का समर्थन नहीं करते हैं!
  • हालांकि, हम अभी भी नकल करते हैं , क्योंकि हम पारित संसाधन को स्थानांतरित नहीं कर सकते हैं , या क्योंकि इसे "स्थानांतरित" करने का कोई वास्तविक अर्थ नहीं है।

निम्नलिखित उपयोग का मामला IMHO हो सकता है, क्योंकि कास्ट के संदर्भ में संदर्भ के लिए एक अच्छा उपयोग मामला है , हालांकि भाषा ने इस दृष्टिकोण को नहीं लेने का फैसला किया ( मूल एसओ पोस्ट देखें )।


मामला: कच्चे सूचक से स्मार्ट पॉइंट्स कंस्ट्रक्टर

यह आमतौर पर उपयोग करने के लिए उचित होगा make_uniqueऔरmake_shared , लेकिन दोनों unique_ptrका shared_ptrनिर्माण कच्चे सूचक से किया जा सकता है। दोनों कंस्ट्रक्टर पॉइंटर को वैल्यू द्वारा प्राप्त करते हैं और इसे कॉपी करते हैं। दोनों अनुमति देते हैं (अर्थात के रूप में: को रोकने के लिए नहीं ) निर्माण में उन्हें करने के लिए पारित मूल सूचक का एक निरंतर उपयोग।

निम्नलिखित कोड डबल फ्री के साथ संकलित करता है और परिणाम देता है :

int* ptr = new int(9);
std::unique_ptr<int> p { ptr };
// we forgot that ptr is already being managed
delete ptr;

दोनों unique_ptrऔर shared_ptrउपरोक्त को रोक सकते हैं यदि उनके संबंधित निर्माता कच्चे संकेतक को एक तालमेल के रूप में प्राप्त करने की उम्मीद करेंगे , उदाहरण के लिए unique_ptr:

unique_ptr(T* const&& p) : ptr{p} {}

जिस मामले में डबल फ्री है उपरोक्त कोड संकलित नहीं होगा, लेकिन निम्नलिखित होगा:

std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership
std::unique_ptr<int> p2 { new int(7) };     // ok, rvalue

ध्यान दें कि ptr यह स्थानांतरित होने के बाद भी इस्तेमाल किया जा सकता है, इसलिए संभावित बग पूरी तरह से नहीं चला गया है। लेकिन अगर उपयोगकर्ता को std::moveइस तरह के बग को कॉल करना आवश्यक है , तो सामान्य नियम में आ जाएगा: एक संसाधन का उपयोग न करें जो ले जाया गया था।


एक पूछ सकता है: ठीक है, लेकिन क्यों T* कास्ट&& p?

कारण सरल है, unique_ptr कास्ट पॉइंटर से निर्माण की अनुमति देने के लिए । याद रखें कि स्थिरांक rvalue संदर्भ बस की तुलना में अधिक सामान्य है rvalue संदर्भ के रूप में यह दोनों स्वीकार करता है constऔरnon-const । तो हम निम्नलिखित की अनुमति दे सकते हैं:

int* const ptr = new int(9);
auto p = std::unique_ptr<int> { std::move(ptr) };

अगर हम सिर्फ रेवल्यू रेफ़रेंस (संकलन त्रुटि: उम्मीद नहीं कर सकते, तो रिवल्यूड को रेव्यू नहीं बाँध सकते ) जाएगा।


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


मैं समान विचारों वाले लोगों में से था, लेकिन मुझे आगे बढ़ने के लिए समर्थन नहीं था।
लाल .वह

"ऑटो p = std :: unique_ptr {std :: move (ptr)};" त्रुटि के साथ संकलित नहीं करता है "वर्ग टेम्पलेट तर्क कटौती विफल"। मुझे लगता है कि यह "unique_ptr <int>" होना चाहिए।
ज़हुई लिन

4

उन्हें अनुमति दी जाती है और यहां तक ​​कि कार्यों के आधार पर रैंक की जाती है const, लेकिन चूंकि आप द्वारा निर्दिष्ट कास्ट ऑब्जेक्ट से नहीं जा सकते हैं const Foo&&, इसलिए वे उपयोगी नहीं हैं।


"रैंक" टिप्पणी से आपका वास्तव में क्या मतलब है? ओवरलोड रिज़ॉल्यूशन के साथ कुछ करना है, मुझे लगता है?
fredoverflow

यदि आप दिए गए प्रकार में एक चाल ctor है जो एक गतिरोध-रेफ लेता है, तो आप एक कॉन्स्टल रनवे-रेफ से क्यों नहीं चल सकते?
फ्रेड नर्क

6
@FredOverflow, ओवरलोड की रैंकिंग इस प्रकार है:const T&, T&, const T&&, T&&
जीन बुशुइव

2
@ पसंदीदा: आप स्रोत को संशोधित किए बिना कैसे आगे बढ़ते हैं?
fredoverflow

3
@ फ़्रेड: म्यूटेबल डेटा सदस्य, या शायद इस काल्पनिक प्रकार के लिए आगे बढ़ने के लिए डेटा सदस्यों को संशोधित करने की आवश्यकता नहीं होती है।
फ्रेड नर्क

3

Std :: Ref के अलावा , मानक पुस्तकालय std :: as_const में const rvalue संदर्भ का भी उपयोग करता है में इसी उद्देश्य के लिए ।

template <class T>
void as_const(const T&&) = delete;

इसका उपयोग std :: वैकल्पिक में वापसी मान के रूप में भी किया जाता है : लिपटे हुए मूल्य को प्राप्त करते समय :

constexpr const T&& operator*() const&&;
constexpr const T&& value() const &&;

साथ ही std :: get में :

template <class T, class... Types>
constexpr const T&& get(const std::variant<Types...>&& v);
template< class T, class... Types >
constexpr const T&& get(const tuple<Types...>&& t) noexcept;

यह मुमकिन है कि लिपटे हुए मूल्य का उपयोग करते समय मूल्य श्रेणी के साथ-साथ आवरण की निरंतरता को बनाए रखने के लिए।

इससे फर्क पड़ता है कि लिपटे ऑब्जेक्ट पर कांस्टेबल रिफ़ल-क्वालिफाइड फ़ंक्शंस को बुलाया जा सकता है या नहीं। उस ने कहा, मुझे पता नहीं है कि कास्ट रिवल्यू रेफ योग्य कार्यों के लिए कोई उपयोग नहीं है।


1

मैं ऐसी स्थिति के बारे में नहीं सोच सकता जहाँ यह सीधे उपयोगी होगी, लेकिन इसका अप्रत्यक्ष रूप से उपयोग किया जा सकता है:

template<class T>
void f(T const &x) {
  cout << "lvalue";
}
template<class T>
void f(T &&x) {
  cout << "rvalue";
}

template<class T>
void g(T &x) {
  f(T());
}

template<class T>
void h(T const &x) {
  g(x);
}

T in g , T कास्ट है, इसलिए f का x एक T कॉन्स्टेबल है।

यह संभवतया f (जब वह ऑब्जेक्ट को स्थानांतरित करने या उसका उपयोग करने का प्रयास करता है) में एक गंभीर त्रुटि के परिणामस्वरूप होता है, लेकिन f एक प्रतिद्वंद्विता-रेफ ले सकता है , ताकि इसे रिवेल्यू को संशोधित किए बिना lvalues ​​पर नहीं बुलाया जा सके (जैसा कि बहुत सरल है) ऊपर उदाहरण)।

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