2016-01-14 5 views
6

मुझे रेंज-लूप का उपयोग करते समय संदर्भों को लटकाना पड़ रहा है। जाहिर हैमैं अभिव्यक्ति के लिए एक अस्थायी जीवनकाल कैसे बढ़ा सकता हूं?

Wheel() 
Wheel() 
Bike() 
~Bike() with 0 inflated wheels. 
~Wheel() 
~Wheel() 
Wheel::inflate() 
Wheel::inflate() 

कुछ बहुत गलत हो रहा है: निम्नलिखित सी ++ 14 अभिव्यक्ति (पूर्ण उदाहरण नीचे कार्यक्रम) पर विचार करें:

for(auto& wheel: Bike().wheels_reference()) 
     wheel.inflate(); 

यह उत्पादन होता है। पहियों उनके जीवनकाल परे एक्सेस किया जाता है और परिणाम 0 है, नहीं की उम्मीद 2.

एक आसान ठीक main में Bike के लिए एक चर शुरू करने की है। हालांकि, मैं main या Wheel में कोड को नियंत्रित नहीं करता हूं। मैं केवल संरचना Bike बदल सकता हूं।

क्या इस उदाहरण को ठीक करने के लिए कोई तरीका है केवल Bike बदलकर?

एक सफल समाधान समाधान या तो संकलन समय में विफल हो जाएगा, या 2 फुलाए गए टायरों की गणना करेगा और किसी भी वस्तु को उनके जीवनकाल से परे स्पर्श नहीं करेगा।

परिशिष्ट:

#include <memory> 

struct Bike 
{ 
    // Bike() { cout << " FakeBike()" << endl; } 
    // ~Bike() { cout << "~FakeBike()" << endl; } 
    struct RealBike; 
    struct Wrap { 
     std::shared_ptr<RealBike> parent; 
     auto begin() { return parent->wheels.begin(); } 
     auto end() { return parent->wheels.end(); } 
    }; 
    struct RealBike { 
     RealBike() { cout << " Bike()" << endl; } 
     ~RealBike() { 
      cout << "~Bike() with " << std::count_if(wheels.begin(), wheels.end(), 
       [](auto& w) { return w.inflated; }) << " inflated wheels." << endl; 
     } 
     std::array<Wheel, 2> wheels; 
    }; 
    std::shared_ptr<RealBike> real = std::make_shared<RealBike>(); 
    Wrap wheels_reference() { return Wrap{real}; } 
}; 

क्या मुझे पसंद नहीं है कि यह लपेटकर सभी std::array<Wheel, 2> की एपीआई की आवश्यकता है: संकलन तैयार स्रोत

#include <cstdlib> 
#include <iostream> 
#include <array> 
#include <algorithm> 
using std::cout; 
using std::endl; 

struct Wheel 
{ 
    Wheel() { cout << " Wheel()" << endl; } 
    ~Wheel() { cout << "~Wheel()" << endl; } 
    void inflate() { inflated = true; cout << " Wheel::inflate()" << endl; } 
    bool inflated = false; 
}; 

struct Bike 
{ 
    Bike() { cout << " Bike()" << endl; } 
    ~Bike() { 
     cout << "~Bike() with " << std::count_if(wheels.begin(), wheels.end(), 
      [](auto& w) { return w.inflated; }) << " inflated wheels." << endl; 
    } 
    std::array<Wheel, 2>& wheels_reference() { return wheels; } 
    std::array<Wheel, 2> wheels{Wheel(), Wheel()}; 
}; 

int main() 
{ 
    for(auto& wheel: Bike().wheels_reference()) 
     wheel.inflate(); 
    return EXIT_SUCCESS; 
} 
+0

यदि केवल 'बाइक' में, फ़ंक्शन 'संदर्भ' की तुलना में, मान द्वारा सरणी वापस करनी चाहिए, संदर्भ के अनुसार नहीं, लेकिन मुझे लगता है कि यह वही नहीं है जो आप चाहते हैं। – ForEveR

+0

@ForEveR लेकिन 'ऑटो' 'उस से बंधे नहीं जा सका। – TartanLlama

+0

@ForEveR: हालांकि यह उपयोग के बाद नष्ट हो जाता है, यह समाधान के लिए मेरी शर्तों को पूरा नहीं करता है। मुद्रित मान 0 होगा, न कि 2. – Remco

उत्तर

6

wheels_reference के रावल्यू ओवरलोड को हटाएं।

std::array<Wheel, 2>& wheels_reference() & { return wheels; } 
std::array<Wheel, 2>& wheels_reference() && = delete; 

इस तरह आप अस्थायी के सदस्य को संदर्भ नहीं देंगे।

Bike वर्ग

for(auto& wheel: Bike().wheels_reference()) 
    wheel.inflate(); 

का आपका उपयोग का उदाहरण तो (बजना 3.4 उत्पादन) के साथ संकलित करने के लिए मना कर दिया होगा:

test.cpp:31:29: error: call to deleted member function 'wheels_reference' 
    for(auto& wheel: Bike().wheels_reference()) 
        ~~~~~~~^~~~~~~~~~~~~~~~ 
test.cpp:24:27: note: candidate function has been explicitly deleted 
    std::array<Wheel, 2>& wheels_reference() && = delete; 
         ^
test.cpp:23:27: note: candidate function not viable: no known conversion from 'Bike' to 'Bike' for object argument 
    std::array<Wheel, 2>& wheels_reference() & { return wheels; } 

अस्थायी के जीवनकाल मैन्युअल बढ़ा दिया गया है, तो चीजें काम।

Bike&& bike = Bike(); 
for(auto& wheel: bike.wheels_reference()) 
    wheel.inflate(); 
+0

बिल्कुल सही! यह मेरी समस्या को हल करना चाहिए। – Remco

+0

मैं गैर बाहर निकलने वाले फ़ंक्शन और "std :: array और wheels_reference() && = delete के बारे में परेशान हूं;" –

+0

@ डाइटर लुकिंग यह जांचें http://en.cppreference.com/w/cpp/language/member_functions#const-.2C_volatile-.2C_and_ref-qualified_member_functions – jepio

1

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

3

सबसे अच्छा समाधान अस्थायी पर सदस्य फ़ंक्शन कॉल के माध्यम से किसी प्रकार के सदस्यों को प्राप्त करना बंद करना है।

तो wheels_reference एक गैर सदस्य समारोह थे, तो आप बस इसे इस तरह की घोषणा कर सकता है:

wheels_reference(Bike &bike); 

के बाद से एक गैर स्थिरांक lvalue पैरामीटर एक अस्थायी से जुड़ी नहीं किया जा सकता है, तो आप wheels_reference(Bike()) कॉल करने में असमर्थ होगा।चूंकि wheels_reference एक सदस्य समारोह है, तो आप सिर्फ एक ही बात कह रही है के लिए सदस्य समारोह वाक्य रचना का उपयोग करना होगा:

std::array<Wheel, 2>& wheels_reference() & //<-- 
{ return wheels; } 

उपयोगकर्ता अब Bike().wheels_reference() कॉल करने के लिए प्रयास करता है, संकलक शिकायत करेंगे।

+0

बिल्कुल सही! अनिवार्य रूप से @ jeplo के समाधान के समान। गैर-सदस्य कार्यों के साथ समानता अंतर्दृष्टिपूर्ण है। – Remco

1

तुम बस wheels_reference सदस्य समारोह के सीवी-रेफरी योग्य overloadings के एक जोड़े में जोड़ सकते हैं: अगर वस्तु अस्थायी (&& मामले) है,

std::array<Wheel, 2>& wheels_reference() & { return wheels; } 

std::array<Wheel, 2> const & wheels_reference() const & { return wheels; } 

std::array<Wheel, 2> wheels_reference() && { return std::move(wheels); } 

std::array<Wheel, 2> wheels_reference() const && { return wheels; } 

ध्यान दें, तो आप एक मूल्य वापस चाहिए (कॉपी-निर्माण डेटा सदस्य से या इससे भी बेहतर कदम-निर्मित), न ही संदर्भ।

सभी चार अधिभारों को आप सभी उपयोग-मामलों को कवर करते हैं।

संबंधित मुद्दे