2008-12-10 36 views
7

Vì vậy, tôi đang cố gắng loại bỏ std :: vector's bằng cách sử dụng boost :: ptr_vector. Bây giờ tôi đang cố gắng loại bỏ một phần tử từ một phần tử và xóa phần tử đã xóa. Điều rõ ràng nhất đối với tôi là:Cách xóa các phần tử khỏi tăng :: ptr_vector

class A 
{ int m; }; 

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

Nhưng điều này thậm chí sẽ không biên dịch (xem bên dưới để biết thông báo lỗi đầy đủ). Tôi đã thử xóa/loại bỏ thành ngữ như tôi sẽ trên một std :: vector nhưng tất cả các thuật toán của boost :: ptr_vector lần lượt ra được hơi khác nhau từ những người trong std :: vector.

Vì vậy, câu hỏi của tôi:

  • Làm thế nào để loại bỏ một con trỏ từ một ptr_vector?
  • Tôi vẫn cần phải xóa thủ công() phần tử mà tôi đã xóa?

biên dịch báo lỗi:

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 ========== 

Trả lời

9

Bạn cũng có thể làm điều đó với vectơ std :: vectơ.

Trong cả hai trường hợp, xóa mất một trình lặp làm tham số.
Vì vậy, trước khi bạn có thể xóa nội dung nào đó từ vectơ (hoặc ptr_vector), bạn cần xác định vị trí đó.

Cũng lưu ý rằng ptr_vector xử lý nội dung của nó như thể bạn đã lưu trữ một đối tượng không phải là một con trỏ. Vì vậy, bất kỳ tìm kiếm được thực hiện thông qua đối tượng.

Vì vậy, về cơ bản

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 

Ví dụ:

#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

tôi nghĩ rằng bạn đã đúng về câu trả lời của tôi dưới đây. nếu tôi hiểu nó đúng, phân bổ mặc định (heap_clone_allocator) nhân bản các đối tượng chính nó khi tái phân bổ). nó sẽ làm việc nếu sử dụng view_clone_allocator. Tôi đã xóa câu trả lời của tôi và upvoted bạn. vui vẻ :) –

+0

Cảm ơn bạn, vấn đề của tôi là tôi đã không định nghĩa toán tử == cho A * const và dường như là cần thiết. Để có được ví dụ của bạn để biên dịch (VC9), tôi đã phải thay đổi "Một const & rhs" thành "A * const & rhs" và thay đổi nội dung của cơ thể cho phù hợp. Điều đó làm cho nó khó sử dụng với các lớp thư viện. – Roel

+0

Bạn đang thiếu điểm! Ptr_vector <> lưu trữ đối tượng như chúng là một đối tượng. Thay vì làm đảo lộn toán tử bình đẳng, chỉ cần bỏ tham chiếu đến con trỏ. Nếu bạn muốn tìm một con trỏ chính xác, bạn cần sử dụng hàm find_if và truyền một vị từ. –

1

Bạn có thể sử dụng phương pháp erase_if mẫu.

vec.erase_if(predicate()); 
+0

Nhưng sau đó tôi cần phải viết một vị từ có mục đích đặc biệt mà về cơ bản là một đối tượng hàm so sánh đơn giản? Thật là một mớ hỗn độn, nếu đó là cách tôi phải làm việc với ptr_vector Tôi sẽ chỉ gắn bó với vectơ của shared_ptr:/ – Roel

+0

Sử dụng boost :: lambda để viết biến vị ngữ thành hàm lambda (tại chỗ). – paxos1977

3

Tôi nghĩ bạn muốn gọi .release() trên vectơ thay vì xóa. Điều đó loại bỏ các mục nhập và xóa bộ nhớ.

Xem phần "Chức năng mới" để biết chi tiết trong the tutorial hoặc kiểm tra the reference.

Hoặc, bạn cần phải có một trình lặp cho một phần tử để gọi xóa(), tôi chắc chắn rằng một số * tính theo ptr_vector.

+0

Không - 'release' loại bỏ con trỏ khỏi vùng chứa và vùng chứa co lại, nhưng đối tượng không bị xóa. Nó có cùng ngữ nghĩa như 'auto_ptr'' release' - bạn chỉ sử dụng nó để truyền quản lý. – EML

0

Bạn cần sử dụng phương pháp erase_if thành viên có biến vị ngữ phù hợp. Không cần phải xóa con trỏ, vùng chứa có quyền sở hữu.

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

vec.erase_if(delete_a()); 

(lưu ý đây chỉ là một ví dụ chọn vì đơn giản, đối với tình huống như vậy trong mã thực Tôi cho rằng người ta sẽ viết một combo phù hợp bind/equal_to, hoặc sử dụng lambda)

Hoặc, như một sự thay thế, phát hành cuộc gọi trên trình lặp chính xác, nếu bạn vẫn muốn sử dụng đối tượng.

1

Ngữ nghĩa của ptr_vector rất giống với vector thông thường. Bạn phải tìm một yếu tố trước khi bạn có thể xóa nó.

+0

Đúng, xóa mất một trình lặp, ptr_vector là không khác nhau. –

+0

Tôi đoán tôi cần một ptr_iterator, nhưng cái đó dường như được bảo vệ (mặc dù tôi có thể tìm thấy các bài gửi đến danh sách thư nơi nó được sử dụng, vì vậy tôi đoán nó đã được bảo vệ sau này ...). – Roel

1

điều Tò mò: STL::vector<> là một Random Access Container, có nghĩa là nó sử dụng Random Access Iterators.

Vì vậy vec.erase (vec.begin() + N) sẽ loại bỏ các phần tử tại chỉ số N.

Lưu ý rằng làm như vậy phá vỡ toàn bộ iterator meme và bạn có thể không còn trivially chuyển qua lại giữa vector và danh sách ...

Các vấn đề liên quan