2012-04-13 8 views
6

में स्मार्ट पॉइंटर्स का उपयोग करके मैंने एक फ़ंक्शन लिखा है जो फ़ाइल से बाइट लोड करता है और एक फ़ाइलडेटा स्ट्रक्चर देता है जिसमें बाइट बफर और बफर की लंबाई होती है।संरचना या कक्षा

मैं चाहता हूं कि बफर को जितना जल्दी उपभोग किया जाए और स्कोप से बाहर फेंक दिया जाए।

मुझे विभिन्न कास्टिंग त्रुटियों के कारण संकलन करने में समस्या हो रही है। साथ ही, मुझे यकीन नहीं है कि बफर को कॉपी करने के बजाए सही ढंग से स्थानांतरित किया जा रहा है या नहीं। मुझे फ़ाइलडेटा स्ट्रक्चर की प्रतिलिपि नहीं है, क्योंकि यह शायद 16 बाइट्स है।

सामान्य रूप से, आप कक्षा पॉइंटर्स के रूप में स्मार्ट पॉइंटर्स का उपयोग कैसे करते हैं? क्या वह कुछ भी है जो आप करेंगे?

यह एक घबराहट सवाल है, मुझे पता है, लेकिन चूंकि मुझे सामान्य रूप से स्मार्ट पॉइंटर्स के साथ कुछ वैचारिक कठिनाइयों का सामना करना पड़ रहा है, इसलिए मुझे आशा है कि यह उदाहरण मुझे सही दिशा में मदद करेगा।

यहाँ मैं अब तक क्या मिल गया है:

struct FileData 
{ 
    unique_ptr<char[]> buf; 
    unsigned int len; 
}; 

FileData LoadFile(string filename) 
{ 
    ifstream str; 
    str.open(filename, ios::binary); 

    str.seekg(0, ios::end); 
    auto len = str.tellg(); 
    str.seekg(0, ios::beg); 

    char* buf = new char[len]; 

    str.read(buf, len); 
    str.close(); 

    FileData d = { unique_ptr<char[]>(buf), len }; 

    return d; 
} 

संपादित करें: कुछ लोगों के बाद से, त्रुटि संदेश है कि मैं इस वर्तमान कोड के साथ मिल के बारे में उत्सुक हैं यहाँ यह है:

error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>' 
+0

आपकी समस्या यह है कि आप त्रुटि संदेशों के बारे में कोई विशिष्ट विवरण नहीं देते हैं। पृथ्वी पर हम कैसे संभवतः उन्हें पहचान सकते हैं? – Puppy

+0

@DeadMG मुझे लगता है कि यह स्पष्ट होगा कि कोड के साथ समस्याएं हैं, क्योंकि मैंने यह इंगित किया था कि मुझे यकीन नहीं है कि यह स्मार्ट पॉइंटर्स का उपयोग करने और अर्थशास्त्र को स्थानांतरित करने का सही तरीका है। मैं कोड संकलन से अधिक करना चाहता हूँ; मैं इसे सही और मूर्खतापूर्ण बनाना चाहता हूं। फिर भी, मैंने त्रुटि संदेश के साथ प्रश्न अद्यतन किया है। –

+0

आपको जो त्रुटि मिल रही है वह इसलिए है क्योंकि आप एक unique_ptr की प्रतिलिपि बनाने का प्रयास कर रहे थे, आपको std :: move का उपयोग करना होगा। आप एक साझा_पीटीआर का इस्तेमाल कर सकते थे और अपना खुद का डीलोकेटर घोषित कर सकते थे, लेकिन वेक्टर समाधान बहुत साफ है। – pstrjds

उत्तर

5

आपका कोड, ठीक है एक छोटी सी विस्तार के लिए छोड़कर:

struct FileData 
{ 
    unique_ptr<char[]> buf; 
    <del>unsigned int</del> <ins>streamoff</ins> len; 
}; 

कारण यह आप के लिए संकलन नहीं है कि आपके संकलक कि है अभी तक विशेष चाल सदस्यों की स्वचालित पीढ़ी को लागू नहीं करता है। एक पूरी तरह से सी ++ 11 अनुरूप संकलक में अपने FileData कैसा व्यवहार करेंगे, जैसे कि:

struct FileData 
{ 
    unique_ptr<char[]> buf; 
    streamoff len; 

    FileData(FileData&&) = default; 
    FileData& operator=(FileData&&) = default; 
    FileData(const FileData&) = delete; 
    FileData& operator=(const FileData&) = delete; 
    ~FileData() = default; 
}; 

डिफॉल्ट की चाल निर्माता बस निर्माणों प्रत्येक सदस्य (डिफॉल्ट की चाल कार्य के लिए और इसी तरह) के लिए कदम।

dLoadFile से लौटने पर, एक निहित कदम होता है जो निहित रूप से डिफॉल्ट चालक कन्स्ट्रक्टर से जुड़ जाएगा।

vector<char> या string का उपयोग अन्य लोगों ने सुझाव दिया है कि यह भी काम करेगा। लेकिन सी ++ 11 के संबंध में आपके कोड में कुछ भी गलत नहीं है।

ओह, मैं यह इतना की तरह परिवर्तन कर सकता है:

:

FileData LoadFile(string filename) 
{ 
    ifstream str; 
    str.open(filename, ios::binary); 

    str.seekg(0, ios::end); 
    auto len = str.tellg(); 
    str.seekg(0, ios::beg); 

    FileData d = {unique_ptr<char[]>(new char[len]), len}; 

    str.read(d.buf.get(), d.len); 
    str.close(); 

    return d; 
} 

आप स्पष्ट रूप से FileData चाल सदस्यों परिभाषित करने की जरूरत है, यह की तरह दिखना चाहिए: मैं अपने संसाधनों को जल्दी से जल्दी स्वामित्व प्राप्त करना

struct FileData 
{ 
    unique_ptr<char[]> buf; 
    streamoff len; 

    FileData(FileData&& f) 
     : buf(std::move(f.buf)), 
      len(f.len) 
     { 
      f.len = 0; 
     } 

    FileData& operator=(FileData&& f) 
    { 
     buf = std::move(f.buf); 
     len = f.len; 
     f.len = 0; 
     return *this; 
    } 
}; 

ओह, जो मुझे एक और बिंदु पर लाता है। डिफ़ॉल्ट स्थानांतरित सदस्य बिल्कुल सही नहीं हैं क्योंकि वे स्रोत में len से 0 सेट नहीं करते हैं। यह आपके दस्तावेज़ पर निर्भर करता है अगर यह एक बग है या नहीं। ~FileData() को बफर की लंबाई को दर्शाने के लिए len की आवश्यकता नहीं है। लेकिन अन्य ग्राहक हो सकता है। यदि आप FileData से एक विश्वसनीय len नहीं रखते हैं, तो डिफ़ॉल्ट स्थानांतरित सदस्य ठीक हैं, अन्यथा वे नहीं हैं।

+0

'फ़ाइलडेटा (फ़ाइलडेटा और&) = डिफ़ॉल्ट; '- क्या यह एक शॉर्टंड सिंटैक्स है जो कुछ कंपेलरों पर काम करता है? जब मैं एक स्पष्ट रूप से एक चालक निर्माता बनाने की कोशिश करता हूं, तो यह शिकायत करता है कि 'ऑपरेटर =' पहुंच योग्य नहीं है। हम्म ... (वीसी ++ 11, वैसे) –

+0

@ReiMiyasaka: हां, '= डिफ़ॉल्ट 'वाक्यविन्यास सी ++ 98/03 में स्पष्ट रूप से अनुरोध करने का एक तरीका है जिसे आप स्पष्ट रूप से जेनरेट किए गए विशेष सदस्य के रूप में देखेंगे । डिफ़ॉल्ट ctor के लिए काम करता है, प्रतिलिपि ctor, प्रतिलिपि प्रतिलिपि, ctor ले जाएँ, असाइनमेंट और dtor ले जाएँ। लेकिन यह अभी तक आपके लिए लागू नहीं किया जा सकता है (मैं वीसी ++ 11 से परिचित नहीं हूं)। इन सुविधाओं को गेम में देर से मानकीकृत किया गया था, इसलिए यह समझ में आता है कि आपके कंपाइलर में अभी तक नहीं हो सकता है। "= हटाएं" वाक्यविन्यास लगभग इसे निजी घोषित करने और इसे परिभाषित करने के बराबर नहीं है। मुझे यकीन नहीं है कि आपके स्पष्ट कदम ctor के साथ क्या चल रहा है। –

2

मैं शायद एक std:::unique_ptr<char[]> के बजाय एक std::vector का प्रयोग करेंगे, अगर आप std::vector प्रतिलिपि बनाई जा रही कोई आपत्ति नहीं है तुम वापस कब FileData:

0,123,
struct FileData 
{ 
    vector<char> buf; 
}; 

FileData LoadFile(string filename) 
{ 
    ifstream str; 
    str.open(filename, ios::binary); 

    str.seekg(0, ios::end); 
    auto len = str.tellg(); 
    str.seekg(0, ios::beg); 

    FileData d; 
    d.buf.resize(len); 

    str.read(&(d.buf)[0], len); 
    str.close(); 

    return d; 
} 

वैकल्पिक रूप से, नकल से बचने के लिए, फोन करने वाले एक वापसी मान के बजाय एक समारोह पैरामीटर के रूप में एक FileData में पारित कर सकते हैं:

struct FileData 
{ 
    vector<char> buf; 
}; 

void LoadFile(string filename, FileData &data) 
{ 
    ifstream str; 
    str.open(filename, ios::binary); 

    str.seekg(0, ios::end); 
    auto len = str.tellg(); 
    str.seekg(0, ios::beg); 

    data.buf.resize(len); 

    str.read(&(data.buf)[0], len); 
    str.close(); 
} 
+0

क्या यह फ़ाइल डेटा "सरणी" की प्रतिलिपि नहीं लेता है, या वेक्टर सी ++ 11 चाल semantics लागू करता है? तर्कवादी होने की कोशिश नहीं कर रहा है, सिर्फ उत्सुक है। – pstrjds

+0

उस स्थिति में मुझे फ़ाइलडेटा स्ट्रक्चर की भी आवश्यकता नहीं होगी, ताकि मेरे प्रश्न के आधा जवाब दें। धन्यवाद। मैं इसे एक वेक्टर का आकार बदलने के साथ प्रदर्शन बहुत बुरा नहीं है? –

+1

@Rei: यह दिए गए उदाहरण में आकार बदल नहीं जाएगा। चूंकि यह प्रारंभ में खाली है, यह "आकार" जैसा है: पी और यह स्मृति को आवंटित करने से धीमा नहीं है। – Puppy

-1

कैसे बफर के रूप में std :: स्ट्रिंग का उपयोग के बारे में। यह सब व्यवहार आप चाहते है:

  • संदर्भ गिना बजाय कॉपी किया
  • क्षेत्र से बाहर एक बार गायब हो जाता है
  • मनमाने ढंग से बाइट्स की एक मनमाना राशि

लोग नीचे इस मतदान करेंगे क्योंकि पकड़ अपने स्ट्रिंग के मूल उद्देश्य का उपयोग नहीं; शायद एक वर्ग निकाले जाते हैं (या लपेट) और इसे 'बफ़र'

+0

मुझे लगता है कि यह काम करेगा, लेकिन फिर से, यह मुझे यह समझने में मदद नहीं करता कि मैं अन्य समान परिस्थितियों में स्मार्ट पॉइंटर्स का उपयोग कैसे करूं। –

+0

मैं अद्वितीय_ptr नहीं जानता (मैं बूस्ट का उपयोग करता हूं) लेकिन unique_ptr मुझे गलत लगता है, आमतौर पर सरणी ptrs की अपनी कक्षा होती है। मेरे पास uniq_ptr होगा। मूल रूप से यह – pm100

+0

काम करना चाहिए जब 'std :: string' संदर्भ गिना गया था?या यह विभिन्न संकलकों में कार्यान्वयन-विशिष्ट है? –