2011-11-09 16 views
5

जावा डेवलपर के रूप में मेरे पास निम्न C++ प्रश्न है।ऐरे: ऑब्जेक्ट्स या संदर्भ संग्रहीत

यदि मेरे पास टाइप ए की वस्तुएं हैं और मैं उन्हें एक सरणी में संग्रहित करना चाहता हूं, तो क्या मुझे केवल ऑब्जेक्ट्स को पॉइंटर्स स्टोर करना चाहिए या ऑब्जेक्ट को स्टोर करना बेहतर है?

मेरी राय में पॉइंटर्स को स्टोर करना बेहतर है क्योंकि: 1) कोई आसानी से ऑब्जेक्ट को हटा सकता है, अपने सूचक को शून्य 2 पर सेट करके) एक स्थान बचाता है।

+1

उपयोग और कंटेनर पर निर्भर करता है .. –

+3

मुझे लगता है कि "संदर्भ" के साथ आप पॉइंटर्स का मतलब है। सी ++ में संदर्भ शून्य पर सेट नहीं किए जा सकते हैं, और आप वैसे भी संदर्भों की एक सरणी परिभाषित नहीं कर सकते हैं। – celtschk

+0

कंटेनर एक सरणी है, और ऑब्जेक्ट को रनटाइम – user695652

उत्तर

7

पॉइंटर्स या बस ऑब्जेक्ट्स?

आप सी ++ में किसी सरणी में संदर्भ नहीं डाल सकते हैं। आप संकेत की एक सरणी बना सकते हैं, लेकिन मैं अभी भी नहीं बल्कि संकेत की तुलना में एक कंटेनर और वास्तविक वस्तुओं की पसंद करते हैं क्योंकि:

  1. लीक करने के लिए कोई संभावना नहीं है, अपवाद सुरक्षा से निपटने के लिए आसान है।
  2. यह कम स्थान नहीं है - यदि आप पॉइंटर्स की एक सरणी संग्रहीत करते हैं तो आपको ऑब्जेक्ट के लिए स्मृति और पॉइंटर के लिए स्मृति की आवश्यकता होती है।

केवल बार मैं एक कंटेनर में संकेत डाल (या स्मार्ट संकेत बेहतर होगा) की वकालत चाहते हैं (या सरणी यदि आप चाहिए) है जब आपके वस्तु कंटेनरों के लिए construable और आबंटित एक आवश्यकता नकल नहीं है (, पॉइंटर्स हमेशा यह मिलते हैं) या आपको उन्हें पॉलिमॉर्फिक होने की आवश्यकता है। जैसे

#include <vector> 

struct foo { 
    virtual void it() {} 
}; 

struct bar : public foo { 
    int a; 
    virtual void it() {} 
}; 

int main() { 
    std::vector<foo> v; 
    v.push_back(bar()); // not doing what you expected! (the temporary bar gets "made into" a foo before storing as a foo and your vector doesn't get a bar added) 
    std::vector<foo*> v2; 
    v2.push_back(new bar()); // Fine 
} 

आप इस सड़क boost pointer containers नीचे जाने के लिए ब्याज की हो सकता है क्योंकि वे कड़ी मेहनत के सभी करते हैं आप के लिए चाहते हैं।

सरणी या कंटेनरों से हटा रहा है।

NULL असाइन करने से आपके कंटेनर/सरणी में कोई कम पॉइंटर्स नहीं बनता है, (यह delete या तो संभाल नहीं करता है), आकार वही रहता है लेकिन अब पॉइंटर्स हैं जो आप कानूनी रूप से अपमान नहीं कर सकते हैं। यह आपके कोड के बाकी अधिक बयान करता है, तो अतिरिक्त के रूप में जटिल बना देता है और जैसी चीजों पर प्रतिबंध लगाता है:

// need to go out of our way to make sure there's no NULL here 
std::for_each(v2.begin(),v2.end(), std::mem_fun(&foo::it)); 

मैं वास्तव में सामान्य रूप में संकेत के दृश्यों में NULL रों अनुमति देने का विचार नापसंद है क्योंकि आप जल्दी से सभी दफन अंत सशर्त बयान के अनुक्रम में असली काम।

v2.erase(v2.begin()); 

पहले या v2.begin()+1 पल के लिए दूर करने के लिए: विकल्प है कि std::vector एक erase विधि है कि पुनरावर्तक तो आप लिख सकते हैं लेता है प्रदान करता है। समय जटिलता के कारण std::vector पर हालांकि "एनएच तत्व मिटाएं" विधि आसान नहीं है - यदि आप बहुत सारे मिटा रहे हैं तो अन्य कंटेनर भी अधिक उपयुक्त हो सकते हैं।

एक सरणी आप के साथ मिटा अनुकरण कर सकते हैं के लिए:

#include <utility> 
#include <iterator> 
#include <algorithm> 
#include <iostream> 

int main() { 
    int arr[] = {1,2,3,4}; 
    int len = sizeof(arr)/sizeof(*arr); 
    std::copy(arr, arr+len, std::ostream_iterator<int>(std::cout, " ")); 
    std::cout << std::endl; 

    // remove 2nd element, without preserving order: 
    std::swap(arr[1], arr[len-1]); 
    len -= 1; 
    std::copy(arr, arr+len, std::ostream_iterator<int>(std::cout, " ")); 
    std::cout << std::endl; 

    // and again, first element: 
    std::swap(arr[0], arr[len-1]); 
    len -= 1; 
    std::copy(arr, arr+len, std::ostream_iterator<int>(std::cout, " ")); 
    std::cout << std::endl; 
} 

आदेश संरक्षण एक भी स्वैप, जो अच्छी तरह से मिटा कि std::vector चेहरे की जटिलता को दिखाता है के बजाय शफ़ल की एक श्रृंखला की आवश्यकता है। निश्चित रूप से ऐसा करने से आपने एक बहुत बड़ा पहिया फिर से शुरू किया है, एक मानक लाइब्रेरी कंटेनर की तुलना में बहुत कम उपयोगी और लचीला रूप से आपके लिए मुफ्त में होगा!

+1

शून्य पर पॉइंटर सेट करके किसी ऑब्जेक्ट को "निकालना" प्राकृतिक नहीं है और कोड को अनावश्यक जटिलता जोड़ता है। – slaphappy

+1

1) वास्तविक वस्तुओं को स्थानांतरित करना महंगा हो सकता है (उदाहरण के लिए यदि आप वेक्टर के बीच में डालें) 2) आप वास्तविक वस्तुओं के साथ पॉलिमॉर्फिक कंटेनर नहीं कर सकते हैं। –

+0

@kbok लेकिन आप किसी ऑब्जेक्ट से किसी ऑब्जेक्ट को कैसे हटाएंगे? – user695652

1

ऐसा लगता है जैसे आप पॉइंटर्स के साथ भ्रमित संदर्भ हैं। सी ++ वस्तु का प्रतिनिधित्व करने के 3 आम तरीके है

  • संदर्भ
  • प्वाइंटर
  • मान

जावा से आ रहा है सबसे अनुरूप रास्ता एक सूचक के साथ ऐसा करने के लिए है संभालती है। यह संभावना है कि आप यहां क्या करने की कोशिश कर रहे हैं।

वे कैसे संग्रहीत किए जाते हैं हालांकि उनके व्यवहार पर कुछ सुंदर मौलिक प्रभाव पड़ते हैं। जब आप एक मूल्य के रूप में स्टोर करते हैं तो आप अक्सर मूल्यों की प्रतियों से निपट रहे हैं। जहां पॉइंटर्स एक ऑब्जेक्ट से कई संदर्भों से निपट रहे हैं। एक का एक फ्लैट जवाब देना दूसरे की तुलना में बेहतर है, इन वस्तुओं को

0

पर एक और अधिक संदर्भ के बिना वास्तव में संभव नहीं है, आप एक कंटेनर में संदर्भ संग्रहीत नहीं कर सकते हैं। आप इसके बजाय (नग्न) पॉइंटर्स स्टोर कर सकते हैं, लेकिन यह त्रुटियों के लिए प्रवण है और इसलिए इस पर फंस गया है।

इस प्रकार, असली विकल्प वस्तुओं और स्मार्ट पॉइंटर्स को ऑब्जेक्ट्स में संग्रहीत करने के बीच है। दोनों के पास उनके उपयोग हैं। मेरी सिफारिश मूल्यों के आधार पर वस्तुओं को संग्रहीत करने के साथ होगी जब तक कि विशेष स्थिति अन्यथा मांग न करे। यह भी हो सकता है:

  • अगर आप कंटेनर से इसे हटाने के बिना वस्तु बाहर शून्य पर की जरूरत है;
  • यदि आपको एकाधिक कंटेनर में उसी ऑब्जेक्ट पर पॉइंटर्स स्टोर करने की आवश्यकता है;
  • यदि आपको कंटेनर पॉलिमॉर्फिक के तत्वों का इलाज करने की आवश्यकता है।

एक कारण के लिए नहीं यह, स्थान बचाने के लिए मूल्य द्वारा तत्वों के संचय के बाद से है और अधिक स्थान की कुशल होने की संभावना है।

1

यह पूरी तरह से निर्भर करता है कि आप क्या करना चाहते हैं ... लेकिन आप कुछ तरीकों से गुमराह हैं।

चीजें आपको पता होना चाहिए रहे हैं:

  1. आप, सी ++ में शून्य के लिए एक संदर्भ सेट नहीं कर सकता आप शून्य करने के लिए एक सूचक सेट कर सकते हैं, हालांकि।
  2. एक संदर्भ केवल मौजूदा वस्तु के लिए किया जा सकता है - इसे प्रारंभ करने के लिए शुरू करना चाहिए।
  3. एक संदर्भ बदला नहीं जा सकता है (हालांकि संदर्भित मान हो सकता है)।
  4. आप अंतरिक्ष को सहेज नहीं पाएंगे, असल में आप ऑब्जेक्ट और संदर्भ का उपयोग करने के बाद से अधिक उपयोग करेंगे। यदि आपको एक ही ऑब्जेक्ट को कई बार संदर्भित करने की आवश्यकता है तो आप स्पेस को सेव करते हैं, लेकिन आप पॉइंटर का भी उपयोग कर सकते हैं - यह सबसे अधिक लचीला है (पढ़ना: सभी नहीं) परिदृश्य।
  5. एक अंतिम महत्वपूर्ण: एसटीएल कंटेनर (वेक्टर, सूची, आदि) में कॉप्य अर्थशास्त्र है - वे संदर्भों के साथ काम नहीं कर सकते हैं। वे पॉइंटर्स के साथ काम कर सकते हैं, लेकिन यह जटिल हो जाता है, इसलिए अब आपको उन कंटेनरों में कॉपी करने योग्य वस्तुओं का उपयोग करना चाहिए और स्वीकार करना चाहिए कि उनकी प्रतिलिपि बनाई जाएगी, जैसे या नहीं। एसटीएल को कॉपी अर्थशास्त्र के साथ कुशल और सुरक्षित होने के लिए डिज़ाइन किया गया है।

आशा है कि मदद करता है!:)

पीएस (ईडीआईटी): आप बूस्ट/टीआर 1 (उन्हें Google) में कुछ नई सुविधाओं का उपयोग कर सकते हैं, और साझा_प्टर (संदर्भ गिनती स्मार्ट पॉइंटर्स) का एक कंटेनर/सरणी बना सकते हैं जो आपको जावा के संदर्भों के समान अनुभव देगा और कचरा संग्रह। मतभेदों का झटका है लेकिन आपको इसके बारे में खुद को पढ़ना होगा - वे नए मानक की एक महान विशेषता है।

+0

ठीक कर दूंगा "क्या मुझे ऑब्जेक्ट्स को पॉइंटर्स स्टोर करना चाहिए या ऑब्जेक्ट को स्टोर करना बेहतर है?" –

+0

उनके मूल प्रश्न ने कभी भी एक सूचक का उल्लेख नहीं किया, इसने हर जगह उन संदर्भों का उल्लेख किया जो उनका इलाज करने की कोशिश कर रहे थे क्योंकि उनका उपयोग जावा में किया जाएगा जो संभव नहीं है। ;) –

1

आपको हमेशा ऑब्जेक्ट्स को स्टोर करना चाहिए; इस तरह, कंटेनर आपके लिए वस्तुओं के जीवनकाल का प्रबंधन करेगा।

कभी-कभी, आपको पॉइंटर्स स्टोर करने की आवश्यकता होगी; सबसे आम तौर पर, बेस क्लास के पॉइंटर्स जहां ऑब्जेक्ट्स स्वयं अलग-अलग प्रकार के होंगे। उस स्थिति में, आपको वस्तुओं के जीवनकाल को प्रबंधित करने के लिए सावधान रहना होगा; यह सुनिश्चित करना कि कंटेनर में उन्हें नष्ट नहीं किया जाता है, लेकिन जब उन्हें अब आवश्यकता नहीं होती है तो वे नष्ट हो जाते हैं।

जावा के विपरीत, शून्य के लिए पॉइंटर सेट करना ऑब्जेक्ट को इंगित करता है; इसके बजाए, यदि ऑब्जेक्ट में कोई और पॉइंटर्स नहीं हैं तो आपको मेमोरी रिसाव मिलती है। यदि ऑब्जेक्ट new का उपयोग करके बनाया गया था, तो delete किसी बिंदु पर कॉल किया जाना चाहिए। यहां आपके सर्वोत्तम विकल्प स्मार्ट पॉइंटर्स (shared_ptr, या शायद unique_ptr उपलब्ध होने पर) स्टोर करने के लिए हैं, या बूस्ट के सूचक कंटेनर का उपयोग करने के लिए हैं।

0

aix का जवाब देने के लिए जोड़ने के लिए:

आप बहुरूपी वस्तुओं संग्रहीत करना चाहते हैं, तो आप क्योंकि कंटेनर एक प्रतिलिपि बनाने स्मार्ट संकेत का उपयोग करना चाहिए, और व्युत्पन्न प्रकार के लिए केवल आधार हिस्सा कॉपी (कम से कम मानक वाले, मुझे लगता है कि बूस्ट में कुछ कंटेनर हैं जो अलग-अलग काम करते हैं)। इसलिए आप अपनी वस्तुओं के किसी भी बहुलक व्यवहार (और किसी व्युत्पन्न-वर्ग राज्य) को खो देंगे।

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