2011-07-21 15 views
14

मुझे गतिशील रूप से 1-डी और 2-डी सरणी आवंटित करने की आवश्यकता है जिनके आकार रन-टाइम पर दिए जाते हैं।आवंटित वैक्टर (या वैक्टरों के वैक्टर) गतिशील रूप से

मैं std::vector "खोज" करने में कामयाब रहा और मुझे लगता है कि यह मेरे उद्देश्यों के अनुरूप है, लेकिन मैं यह पूछना चाहता हूं कि मैंने जो लिखा है वह सही है और/या बेहतर किया जा सकता है।

#include <vector> 

typedef std::vector< std::vector<double> > matrix; 

//... various code and other stuff 

std::vector<double> *name = new std::vector<double> (size); 
matrix *name2 = new matrix(sizeX, std::vector<double>(sizeY)); 

उत्तर

45

गतिशील रूप से आवंटित सरणी आवश्यक है जब आपके आयाम रनटाइम पर दिए जाते हैं, जैसा आपने पाया है।

हालांकि, std::vector इस प्रक्रिया के आसपास पहले से ही रैपर है, इसलिए गतिशील रूप से आवंटित वैक्टर एक डबल पॉजिटिव की तरह है। यह अनावश्यक है।

बस लिखें:

#include <vector> 

typedef std::vector< std::vector<double> > matrix; 
matrix name(sizeX, std::vector<double>(sizeY)); 
+0

धन्यवाद, वास्तव में स्पष्ट और सहायक। :) – Federico

+0

@ फेडेरिको: कोई समस्या नहीं :) –

+1

मुझे लगता है कि यह मुझे सबसे अच्छा विवरण मिला है! मेरी समस्या भी हल हो गई। – skr

7

आप दो मुद्दों, गतिशील आवंटन और आकार बदलने योग्य कंटेनर conflating कर रहे हैं:

यह मैं क्या कर रहा है। आप गतिशील आवंटन के बारे में चिंता करने के लिए, बाद से आपके कंटेनर है कि के लिए आप पहले से ही है, तो बस इसे इस तरह कहते हैं की जरूरत नहीं है:

matrix name(sizeX, std::vector<double>(sizeY)); 

यह name स्वत: भंडारण अवधि के साथ एक वस्तु कर देगा, और आप उपयोग कर सकते हैं अपने name[i][j] के माध्यम से सदस्य।

+0

सबसे पहले: उत्तर के लिए धन्यवाद। फिर, पूरी तरह से सुनिश्चित होने के लिए कि मैं आपका उत्तर समझ गया, आपका मतलब है कि मुझे के साथ "नया" की आवश्यकता नहीं है? – Federico

+0

संक्षिप्त उत्तर: वास्तव में, आप नहीं करते हैं। मध्यम उत्तर: यदि आप सी ++ को निष्क्रिय रूप से उपयोग करते हैं, तो आपको कभी भी 'new'' नहीं कहना चाहिए ('unique_ptr' के निर्माता के संभावित अपवाद के साथ)। –

+0

ठीक है, मध्यम जवाब मेरे लिए मुश्किल हो रहा है, क्या आप मुझे एक संदर्भ दे सकते हैं? बस यह समझने के लिए कि "idiomatically" से आपका क्या मतलब है या मुझे 'new' – Federico

3

तुम क्या कर रहे हैं मूल रूप से काम करना चाहिए, तथापि:

सामान्य तौर पर, गतिशील वस्तुओं

आवंटित नहीं है तुम एक चाहते हैं वेक्टर, ऐसा करें:

std::vector<double> vec(size); 

नहीं इस:

std::vector<double>* vec = new std::vector<double>(size); 

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

+0

यदि आप एक थ्रेडेड एप्लिकेशन चला रहे हैं, तो सुनिश्चित करें। मल्टीथ्रेडिंग मेमोरी आवंटन की बात आती है और डॉन की पूरी तरह से नया सेट पेश करती है। – pg1989

+0

@ pg1989: क्या आप सुझाव दे रहे हैं कि बहुप्रचारित अनुप्रयोगों में, आपको अलग-अलग धागे आवंटन और निरस्तीकरण करने की कोशिश करनी चाहिए? नहीं, एक बहुप्रचारित कार्यक्रम में, एक ही नियम लागू होते हैं, * केवल इतना ही *। – jalf

+0

नहीं, मैं साझा संसाधनों की समवर्ती पहुंच का अधिक जिक्र कर रहा था। शायद मैंने इसे सही नहीं बताया। यह सच है कि idiomatic C++ में आपको कभी भी स्पष्ट रूप से नया कॉल नहीं करना चाहिए। हालांकि, आपको अभी भी उन वस्तुओं के बारे में सोचना होगा जिन्हें आप जोड़ रहे हैं जैसे कि आपके पास है, क्योंकि यदि कोई धागा किसी ऑब्जेक्ट को एक्सेस करने का प्रयास करता है जो पहले ही नष्ट हो चुका है, तो बुरी चीजें हो सकती हैं। – pg1989

-1

यदि आपको रन समय पर सरणी आकारों का आकार बदलने की आवश्यकता नहीं है, तो आप केवल मानक सरणी (रनटाइम पर आवंटित) का उपयोग कर सकते हैं!

#include <vector> 

typedef std::vector< std::vector<double> > matrix; 

//... various code and other stuff 

std::vector<double> *name = new std::vector<double> (size); 

matrix *name2 = new matrix(sizeX, std::vector<double>(sizeY)); 

संक्षेप में, सब मेरे द्वारा की गई है एक एकल ब्रैकेट हटाने ((:

हालांकि, अगर आप रनटाइम पर सरणियों का आकार बदलने की जरूरत है, तो आप निम्न (संशोधित) कोड का उपयोग कर सकते)।

+0

हां, ब्रैकेट एक टाइपो था, मैंने इसे मूल पोस्ट से भी हटा दिया: पी – Federico

+0

आपका कोड तब पूरी तरह कार्यात्मक होना चाहिए! – foxy

1

आप कंटेनरों को गतिशील रूप से आवंटित नहीं करते हैं। यदि वे स्वयं मैन्युअल रूप से प्रबंधित नहीं होते हैं, तो वे स्वचालित रूप से आपके लिए स्मृति प्रबंधित कर सकते हैं।

एक वेक्टर जब आप push_back (या insert) के साथ नए आइटम जोड़ने के लिए, आप निर्माता के लिए तर्क के साथ शुरू से ही इसका आकार चुन सकते हैं, और आप इसे बाद में आकार बदल सकते हैं resize विधि के साथ बढ़ता है।

निर्माता के साथ अपने आकारों के साथ वैक्टर का एक वेक्टर बनाना इस तरह दिखता है:

std::vector< std::vector<double> > matrix(size, std::vector<double>(sizeY)); 

इसका मतलब यह है: एक std::vector<double> की size उदाहरणों, प्रत्येक युक्त sizeY युगल (0.0 के लिए शुरू)।

2

यह सही है लेकिन इसे और अधिक कुशल बनाया जा सकता है।

आप को बढ़ावा देने बहुआयामी सरणियों इस्तेमाल कर सकते हैं: http://www.boost.org/doc/libs/1_47_0/libs/multi_array/doc/user.html

या, आप इसके लिए अपने स्वयं के वर्ग को लागू कर सकते हैं और अनुक्रमण अपने आप को संभाल। शायद कुछ इस तरह (जो अच्छी तरह से परीक्षण नहीं किया है):

#include <vector> 
#include <cassert> 
template <typename T, typename A = std::allocator<T> > 
class Array2d 
{ 
public: 
    typedef Array2d<T> self; 
    typedef std::vector<T, A> Storage; 

    typedef typename Storage::iterator  iterator; 
    typedef typename Storage::const_iterator const_iterator; 
    Array2d() : major_(0), minor_(0) {} 
    Array2d(size_t major, size_t minor) 
     : major_(major) 
     , minor_(minor) 
     , storage_(major * minor) 
    {} 

    template <typename U> 
    Array2d(size_t major, size_t minor, U const& init) 
     : major_(major) 
     , minor_(minor) 
     , storage_(major * minor, u) 
    { 
    } 
    iterator begin()    { return storage_.begin(); } 
    const_iterator begin() const { return storage_.begin(); } 
    iterator end()     { return storage_.end(); } 
    const_iterator end() const  { return storage_.end(); } 
    iterator begin(size_t major) { 
     assert(major < major_); 
     return storage_.begin() + (major * minor_); 
    } 
    const_iterator begin(size_t major) const { 
     assert(major < major_); 
     return storage_.begin() + (major * minor_); 
    } 
    iterator end(size_t major) { 
     assert(major < major_); 
     return storage_.begin() + ((major + 1) * minor_); 
    } 
    const_iterator end(size_t major) const { 
     assert(major < major_); 
     return storage_.begin() + ((major + 1) * minor_); 
    } 
    void clear() { 
     storage_.clear(); 
     major_ = 0; 
     minor_ = 0; 
    } 
    void clearResize(size_t major, size_t minor) 
    { 
     clear(); 
     storage_.resize(major * minor); 
     major_ = major; 
     minor_ = minor; 
    } 
    void resize(size_t major, size_t minor) 
    { 
     if ((major != major_) && (minor != minor_)) 
     { 
      Array2d tmp(major, minor); 
      swap(tmp); 

      // Get minimum minor axis 
      size_t const dist = (tmp.minor_ < minor_) ? tmp.minor_ : minor_; 
      size_t m = 0; 
      // copy values across 
      for (; (m < tmp.major_) && (m < major_); ++m) { 
       std::copy(tmp.begin(m), tmp.begin(m) + dist, begin(m)); 
      } 
     } 
    } 
    void swap(self& other) 
    { 
     storage_.swap(other.storage_); 
     std::swap(major_, other.major_); 
     std::swap(minor_, other.minor_); 
    } 
    size_t minor() const { 
     return minor_; 
    } 
    size_t major() const { 
     return major_; 
    } 
    T*  buffer()  { return &storage_[0]; } 
    T const* buffer() const { return &storage_[0]; } 
    bool empty() const { 
     return storage_.empty(); 
    } 
    template <typename ArrRef, typename Ref> 
    class MajorProxy 
    { 
     ArrRef arr_; 
     size_t major_; 

    public: 
     MajorProxy(ArrRef arr, size_t major) 
     : arr_(arr) 
     , major_(major) 
     {} 

     Ref operator[](size_t index) const { 
      assert(index < arr_.minor()); 
      return *(arr_.buffer() + (index + (major_ * arr_.minor()))); 
     } 
    }; 
    MajorProxy<self&, T&> 
    operator[](size_t major) { 
     return MajorProxy<self&, T&>(*this, major); 
    } 
    MajorProxy<self const&, T const&> 
    operator[](size_t major) const { 
     return MajorProxy<self&, T&>(*this, major); 
    } 
private: 
    size_t major_; 
    size_t minor_; 
    Storage storage_; 
}; 
2

जबकि अंक अन्य उत्तर बनाया बहुत सही (गतिशील नई के माध्यम से वेक्टर आवंटित नहीं, बल्कि वेक्टर आवंटन करते हैं) थे , यदि आप वैक्टर और मैट्रिस (जैसे रैखिक बीजगणित) की शर्तों को सोच रहे हैं, तो आप ईजिन मैट्रिक्स लाइब्रेरी का उपयोग करने पर विचार करना चाहेंगे।

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