2010-09-09 56 views
14

có thể xem phần tử tiếp theo trong vùng chứa mà trình vòng lặp hiện trỏ đến mà không thay đổi trình lặp không?Peek phần tử tiếp theo trong hộp chứa STL

Ví dụ trong std :: set,

int myArray[]= {1,2,3,4}; 
set <int> mySet(myArray, myArray+4); 
set <int>::iterator iter = mySet.begin(); 

//peek the next element in set without changing iterator. 

mySet.erase(iter); //erase the element if next element is n+1 
+3

Tại sao không chỉ tạo một bản sao và thúc đẩy một trong những? Hãy chắc chắn rằng bạn kiểm tra xem một trong hai iterator là bằng '.end()' trước khi bạn tiếp tục! – GManNickG

+0

Tôi nghĩ rằng tôi đã nhầm lẫn với iterator với một con trỏ. khi bạn gán một con trỏ cho con trỏ, cả hai sẽ thay đổi nếu một con trỏ thay đổi nhưng tại sao nó không xảy ra trong trường hợp của một trình lặp? – user963241

+0

@GMan: Boost có các chức năng 'trước' và' tiếp theo' để thực hiện điều đó (nó lấy giá trị vòng lặp theo giá trị, do đó tạo một bản sao như bạn đã đề xuất). Xem http://www.boost.org/libs/utility/utility.htm để biết chi tiết. –

Trả lời

13

Không có trình biến đổi nói chung. Trình lặp không được đảm bảo để có thể hoạt động không bị hủy. Ví dụ cổ điển là một Iterator đầu vào thực sự đại diện cho luồng đầu vào cơ bản.

Có điều gì đó phù hợp với loại trình lặp này. A Forward Iterator không làm mất hiệu lực các bản sao trước đó của chính nó bằng hành động di chuyển về phía trước thông qua bộ sưu tập. Hầu hết các trình vòng lặp (bao gồm cả các bộ lặp cho các bộ sưu tập STL) đều có ít nhất các bộ lặp Iterator, nếu không phải là một phiên bản chức năng hơn - chỉ các bộ lặp Iterator đầu vào hoặc đầu ra Iterator bị hạn chế hơn. Vì vậy, bạn có thể chỉ cần tạo bản sao của trình lặp của bạn, tăng bản sao và kiểm tra rằng, sau đó quay lại trình lặp ban đầu của bạn.

Vì vậy, mã cái nhìn của bạn:

set <int>::iterator dupe = iter; 
++dupe; 
// (do stuff with dupe) 
3
set <int>::iterator iter2 = iter; 
++iter2; 
int peekedValue = *iter2; 
0

Bạn luôn có thể tạo một bản sao của iterator và thúc đẩy các bản sao:

set <int>::iterator iter = mySet.begin(); 
set <int>::iterator iterCopy = iter; 
iterCopy++; 
if (*iterCopy == something) 
    mySet.erase(iter); 

Nhưng hãy cẩn thận rằng iterCopy có thể không còn hợp lệ khi bạn xóa iter.

+0

"iterCopy có thể không còn hợp lệ khi bạn xóa lần lặp". Nó sẽ được cho một bộ, nhưng không phải cho tất cả các container STL. Tôi google "SGI STL thiết lập" hoặc bất cứ điều gì khi tôi muốn có một tài liệu tham khảo tốt ... bao gồm tất cả điều này. –

+0

Tuy nhiên, hãy nhận biết rằng SGI là một nguồn tài nguyên tuyệt vời cho STL. Nó không hoàn toàn chính xác như xa như thư viện chuẩn C++ là có liên quan, tuy nhiên. STL chứa nhiều thùng chứa/thuật toán không chuẩn và các vùng chứa là một phần của tiêu chuẩn C++ không khớp với một số chi tiết, đặc biệt là đối với các trình phân bổ. –

0

container chuỗi (vector, deque, và danh sách), bạn có thể gọi trước mà sẽ cung cấp cho bạn một cái nhìn (biết thêm về phần dưới của link này).

0

này sẽ không làm việc cho std::set như bản chất của nó không cho phép các nhà điều hành [], nhưng đối với container mà, bạn có thể làm:

std::vector<int> v; 
v.push_back(3); 
v.push_back(4); 
std::vector<int>::iterator it = v.begin(); 
std::cout << v[it - v.begin() + 1]; 

Nhưng điều này có thể nguy hiểm nếu it điểm đến cuối cùng yếu tố trong thùng chứa; nhưng cũng áp dụng cho giải pháp trên. Ví dụ. bạn sẽ phải kiểm tra trong cả hai trường hợp.

+0

Tại sao sử dụng toán tử '[] khi bạn đã có một trình lặp? Nếu bạn muốn những gì 'nó' hiện trỏ đến, sử dụng' * it'. Nếu bạn muốn những gì iterator sau khi 'nó' trỏ đến, sử dụng một cái gì đó như' * (it + 1) 'hoặc' std :: vector :: iterator it2 (it); std :: advance (it2, 1); * it2; '.Cuối cùng, mã trình bày sẽ chỉ hoạt động với' std :: vector' (nó sẽ không hoạt động với 'std :: deque' chẳng hạn). –

24

C++ 0x thêm chức năng tiện ích tiện dụng, std::next, sao chép một trình lặp, tiến hành nó và trả về trình lặp vòng nâng cao. Bạn có thể dễ dàng viết riêng std::next thực hiện của bạn:

#include <iterator> 

template <typename ForwardIt> 
ForwardIt next(ForwardIt it, 
       typename std::iterator_traits<ForwardIt>::difference_type n = 1) 
{ 
    std::advance(it, n); 
    return it; 
} 

Bạn có thể sử dụng trong ví dụ của bạn như vậy:

if (iter != mySet.end() && next(iter) != mySet.end() && *next(iter) == *iter + 1) 
    mySet.erase(iter); 
+3

+1, không biết rằng đã được thông qua. Ngẫu nhiên, '++ move (iter)' cũng làm như vậy. – Potatoswatter

+0

Tôi không phải là một chuyên gia với các mẫu vì vậy nó đã cho tôi một thời gian để hoàn toàn grok này bit nhỏ của mã và gần như đi với các giải pháp dễ dàng hơn được cung cấp bởi @AndrewShephard. Nhưng vào phút cuối, nhận thấy rằng giải pháp này có chức năng giống nhau (nhưng không giống hệt) đối với mã nguồn 4.4.x và 4.9.x của gcc đặt tại '/ usr/include/C++/$ {gcc_version}/bits/stl_iterator_base_funcs.h' và vì vậy tôi đã đi với giải pháp này thay thế. –

+0

Tôi thấy http://en.cppreference.com/w/cpp/iterator/next nói rằng đó là từ C++ 11, đó là chính xác? – zhangxaochen

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