2008-12-10 11 views
7

तो मैं boost :: ptr_vector का उपयोग कर अपने std :: वेक्टर से छुटकारा पाने की कोशिश कर रहा हूं। अब मैं एक से तत्व को हटाने की कोशिश कर रहा हूं, और हटाए गए तत्व को भी हटा दिया गया है। मेरे लिए सबसे स्पष्ट बात यह थी:बढ़ावा से तत्वों को मिटाने के लिए कैसे करें :: ptr_vector

class A 
{ int m; }; 

boost::ptr_vector<A> vec; 
A* a = new A; 
vec.push_back(a); 
vec.erase(a); 

लेकिन यह संकलित भी नहीं होगा (पूर्ण त्रुटि संदेश के लिए नीचे देखें)। मैंने मिट्टी को मिटा/निकालने की कोशिश की है जैसे कि मैं एक std :: वेक्टर पर होगा लेकिन boost :: ptr_vector के सभी एल्गोरिदम std :: vector में से थोड़ा अलग हो जाते हैं।

तो मेरे सवालों का:

  • मैं एक ptr_vector से एक सूचक को कैसे निकालूं?
  • क्या मुझे अभी भी हटाए गए तत्व को मैन्युअल रूप से हटाने की आवश्यकता है?

संकलक त्रुटि:

1>------ Build started: Project: ptr_vector_test, Configuration: Debug Win32 ------ 
1>Compiling... 
1>ptr_vector_test.cpp 
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2825: 'C': must be a class or namespace when followed by '::' 
1>  c:\users\rvanhout\svn\trunk\thirdparty\boost\mpl\eval_if.hpp(63) : see reference to class template instantiation 'boost::range_const_iterator<C>' being compiled 
1>  with 
1>  [ 
1>   C=A * 
1>  ] 
1>  c:\users\rvanhout\svn\trunk\thirdparty\boost\range\iterator.hpp(63) : see reference to class template instantiation 'boost::mpl::eval_if_c<C,F1,F2>' being compiled 
1>  with 
1>  [ 
1>   C=true, 
1>   F1=boost::range_const_iterator<A *>, 
1>   F2=boost::range_mutable_iterator<A *const > 
1>  ] 
1>  c:\users\rvanhout\svn\trunk\thirdparty\boost\ptr_container\detail\reversible_ptr_container.hpp(506) : see reference to class template instantiation 'boost::range_iterator<C>' being compiled 
1>  with 
1>  [ 
1>   C=A *const 
1>  ] 
1>  c:\tmp\ptr_vector_test\ptr_vector_test.cpp(21) : see reference to function template instantiation 'boost::void_ptr_iterator<VoidIter,T> boost::ptr_container_detail::reversible_ptr_container<Config,CloneAllocator>::erase<A*>(const Range &)' being compiled 
1>  with 
1>  [ 
1>   VoidIter=std::_Vector_iterator<void *,std::allocator<void *>>, 
1>   T=A, 
1>   Config=boost::ptr_container_detail::sequence_config<A,std::vector<void *,std::allocator<void *>>>, 
1>   CloneAllocator=boost::heap_clone_allocator, 
1>   Range=A * 
1>  ] 
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2039: 'const_iterator' : is not a member of '`global namespace'' 
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2146: syntax error : missing ';' before identifier 'type' 
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2208: 'boost::type' : no members defined using this type 
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : fatal error C1903: unable to recover from previous error(s); stopping compilation 
1>Build log was saved at "file://c:\tmp\ptr_vector_test\Debug\BuildLog.htm" 
1>ptr_vector_test - 5 error(s), 0 warning(s) 
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== 

उत्तर

9

ठीक है आप इसे std :: वेक्टर के साथ भी कर सकते हैं।

दोनों मामलों में मिटाए गए पैरामीटर के रूप में एक इटरेटर लेता है।
तो इससे पहले कि आप किसी वेक्टर (या एक ptr_vector) से कुछ मिटा सकते हैं, आपको इसे ढूंढने की आवश्यकता है।

यह भी ध्यान रखें कि ptr_vector इसकी सामग्री का व्यवहार करता है जैसे कि आपने ऑब्जेक्ट को पॉइंटर नहीं रखा है। तो वस्तु के माध्यम से कोई खोज किया जाता है।

तो मूल रूप से

std::vector<A>  x; 
std::ptr_vector<A> y; 

// These two object should behave in exactly the same way. 
// The ONLY difference is inserting values which for y are pointers. 
// Y take ownership of the pointer and all subsequent acesses to the 
// members of y look like they are objects 

उदाहरण:

#include <boost/ptr_container/ptr_vector.hpp> 
#include <vector> 

class A 
{ int m; 
    public: 
    A(int x):m(x) {} 
    bool operator==(A const& rhs) {return m = rhs.m;} 
}; 

int main() 
{ 
    boost::ptr_vector<A> x; 
    x.push_back(new A(1)); 
    x.erase(std::find(x.begin(),x.end(),A(1))); 


    std::vector<A>   y; 
    y.push_back(A(2)); 
    y.erase(std::find(y.begin(),y.end(),A(2))); 

    // To find an exact pointer don't modify the equality. 
    // Use find_if and pass a predicate that tests for a pointer 
    A* a = new A(3); 
    boost:ptr_Vector<A>  z; 
    z.push_back(a); 
    z.erase(std::find_if(y.begin(),y.end(),CheckPointerValue(a)); 
} 

struct CheckPointerValue 
{ 
    CheckPointerValue(A* a):anA(a) {} 
    bool operator()(A const& x) { return &X == anA;} 
    private: 
     A* anA; 
}; 
+0

मुझे लगता है कि आप नीचे मेरे उत्तर के बारे में सही थे। अगर मैं इसे सही समझता हूं, तो डिफ़ॉल्ट आवंटक (heap_clone_allocator) पुन: आवंटित करते समय ऑब्जेक्ट्स को क्लोन करता है)। हालांकि view_clone_allocator का उपयोग करते हुए यह काम करता। मैंने अपना जवाब हटा दिया है और आपको ऊपर उठाया है। मज़े करें :) –

+0

धन्यवाद, मेरी समस्या यह थी कि मैंने ए * कॉन्स के लिए == ऑपरेटर को परिभाषित नहीं किया था और जो आवश्यक लगता है। संकलन (वीसी 9) के लिए अपना उदाहरण प्राप्त करने के लिए, मुझे "ए कॉन्स एंड आरएस" को "ए * कॉन्स एंड आरएस" में बदलना पड़ा और उसके अनुसार शरीर की सामग्री को बदलना पड़ा। हालांकि लाइब्रेरी कक्षाओं के साथ इसका उपयोग करना मुश्किल हो जाता है। – Roel

+0

आप बिंदु खो रहे हैं! Ptr_vector <> ऑब्जेक्ट को स्टोर करता है जैसे कि वे एक ऑब्जेक्ट हैं। समानता ऑपरेटर को प्रतिबिंबित करने के बजाय पॉइंटर को डी-रेफरेंस करें। यदि आप एक सटीक सूचक खोजना चाहते हैं तो आपको find_if का उपयोग करने और भविष्यवाणी करने की आवश्यकता है। –

1

आप टेम्पलेट विधि erase_if उपयोग कर सकते हैं।

vec.erase_if(predicate()); 
+0

लेकिन फिर मुझे एक विशेष उद्देश्य पूर्वानुमान लिखना होगा जो मूल रूप से एक साधारण तुलना फ़ंक्शन ऑब्जेक्ट है? क्या गड़बड़ है, अगर मुझे जिस तरह से मुझे ptr_vector के साथ काम करना है, तो मैं सिर्फ अपने_क्रेटर्स के साझाकर्ता के साथ रहूंगा:/ – Roel

+0

लम्बा कार्य (स्थान पर) के रूप में भविष्य को लिखने के लिए boost :: lambda का उपयोग करें। – paxos1977

3

मुझे लगता है कि आप मिटाए जाने के बजाय वेक्टर पर .release() को कॉल करना चाहते हैं। यह प्रविष्टि को हटा देता है और स्मृति को हटा देता है।

the tutorial में विवरण के लिए "नया कार्य" अनुभाग देखें, या the reference देखें।

वैकल्पिक रूप से, आपको मिटाएं() को कॉल करने के लिए किसी तत्व को पुनरावर्तक प्राप्त करने की आवश्यकता है, मुझे यकीन है कि एक एटी * ptr_vector के संदर्भ में गिना जाता है।

+0

नहीं - 'रिलीज' कंटेनर से पॉइंटर को हटा देता है, और कंटेनर घटता है, लेकिन ऑब्जेक्ट हटा नहीं जाता है। यह वही अर्थशास्त्र है जो 'auto_ptr'' रिलीज' के रूप में है - आप इसे प्रबंधन को स्थानांतरित करने के लिए उपयोग करते हैं। – EML

0

आपको एक उपयुक्त भविष्यवाणी के साथ सदस्य erase_if विधि का उपयोग करने की आवश्यकता है। सूचक को हटाने की कोई आवश्यकता नहीं है, कंटेनर का स्वामित्व है।

struct delete_a { 
    bool operator()(boost::ptr_vector<A>::value_type inA) { 
     return inA == a; 
    } 
} 

vec.erase_if(delete_a()); 

(ध्यान दें कि यह सिर्फ एक उदाहरण सादगी के लिए चुना है, असली कोड में ऐसी स्थिति मुझे लगता है एक एक उपयुक्त बाँध/equal_to कॉम्बो, या उपयोग लैम्ब्डा लिखते थे के लिए)

या, एक विकल्प के रूप, यदि आप अभी भी ऑब्जेक्ट का उपयोग करना चाहते हैं, तो सही इटरेटर पर कॉल रिलीज करें।

1

ptr_vector के अर्थशास्त्र नियमित vector के समान हैं। इससे पहले कि आप इसे मिटा सकते हैं, आपको तत्व ढूंढना होगा।

+0

हां, मिटाने वाला एक इटरेटर लेता है, ptr_vector कोई अलग नहीं है। –

+0

मुझे लगता है कि मुझे एक ptr_iterator की आवश्यकता है, लेकिन वह एक संरक्षित प्रतीत होता है (हालांकि मुझे मेलिंग सूचियों पर पोस्टिंग मिल सकती है जहां इसका उपयोग किया गया था, इसलिए मुझे लगता है कि इसे बाद में संरक्षित किया गया था ...)। – Roel

1

जिज्ञासु बात: STL::vector<> एक Random Access Container है, जिसका अर्थ है कि यह Random Access Iterators उपयोग करता है।

तो vec.erase (vec.begin() + N) सूचकांक एन पर तत्व निकाल देंगे

ध्यान दें कि ऐसा करने से पूरे इटरेटर मेम टूट जाता है और आप अब तुच्छता बीच स्विच कर सकते वैक्टर और सूचियां ...

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