2012-06-17 43 views
7

Cách thanh lịch nhất để thực hiện vòng lặp là gì và dừng sau phần tử thứ hai thành phần tử cuối cùng (trong C++ 11)?Dừng trên bộ lặp phần tử cuối cùng C++

Lưu ý: Ý tôi là đối với các trình vòng lặp hai chiều; các trình vòng lặp truy cập ngẫu nhiên là một trường hợp đặc biệt tầm thường, tất nhiên, bởi vì chúng có các toán tử +-.

std::list<double> x{1,2,3,4,5,6}; 

for (auto iter = x.begin(); iter != x.end(); ++iter) { 
    auto iter2 = iter; 
    ++iter2; 
    if (iter2 == x.end()) break; 
    std::cout << *iter << std::endl; 
} 
+0

Bạn có chắc chắn bạn không có nghĩa là "các trình vòng lặp chuyển tiếp" thay vì "các trình vòng lặp hai chiều" không? Trường hợp hai chiều có vẻ khá tầm thường. –

+0

@LucTouraille 'std :: list' cung cấp cho trình vòng lặp hai chiều, vì vậy điều đó tốt với tôi-- bạn có thể hiển thị giải pháp tầm thường mà bạn đang nghĩ tới không? – user

+0

Nếu 'while (iter! = X.end() - 1)' là tầm thường đối với bạn, thì 'while (iter! = --x.end())' cũng khá đơn giản, phải không? –

Trả lời

14

Sử dụng std::prev chức năng:

std::list<double> x{1,2,3,4,5,6}; 

for (auto iter = x.begin(); iter != std::prev(x.end()); ++iter) { 
    std::cout << *iter << std::endl; 
} 
+0

Tôi không thể nói tôi thấy bất cứ điều gì đặc biệt hấp dẫn về 'std :: prev' ở đây. Thêm đánh máy là tốt hơn? ; -] – ildjarn

+0

@ildjarn Vâng, tôi đã có một chút nhầm lẫn bởi "thứ hai đến phần tử cuối cùng" và nghĩ rằng nó sẽ là 'std :: prev (x.end(), 2)': S –

+0

Điều này có tác dụng nếu 'x. bắt đầu() == x.end() '? –

5

Trong C++ 03 nó đã có:

for (std::list<double>::iterator it = x.begin(), it_last = --x.end(); 
    it != it_last; ++it) 
{ 
    std::cout << *it << '\n'; 
} 

Trong C++ 11, không có gì khác biệt cơ bản là, nó chỉ là ít verbose ..:

for (auto it = begin(x), it_last = --end(x); it != it_last; ++it) 
{ 
    std::cout << *it << '\n'; 
} 
+0

'x.end() -' phải là '--x.end()'. –

+0

@Luc: Vâng, tôi đã nghĩ rằng '--end (x)' sẽ không làm việc cho các trình vòng lặp nói chung (tức là nếu trình vòng lặp thực tế chỉ là một con trỏ), nhưng sau đó tôi nhận ra rằng 'end (x) - -' cũng vậy. :-P – ildjarn

+0

Trong thực tế, điều này có thể được gõ nhiều hơn câu trả lời của R. Martinho, bởi vì điều đó làm việc cho bất kỳ iterator hai chiều, trong khi điều này không. Vì vậy, nếu được sử dụng trong một thuật toán mà có một iterator, điều này sẽ cần một trong hai chuyên ngành/quá tải cho con trỏ hoặc thẻ công văn cho iterator truy cập ngẫu nhiên nói chung. Nhưng nếu 'std :: list' được dự định là toàn bộ câu hỏi, thay vì chỉ là một ví dụ, thì điều này sẽ làm. –

1

Một cải tiến nhẹ trên R. Martinho Fernandes câu trả lời:

Sử dụng std::prev chức năng:

std::list<double> x{1,2,3,4,5,6}; 

for (auto iter = x.begin(), end=std::prev(x.end()); iter != end; ++iter) { 
    std::cout << *iter << std::endl; 
} 

này chỉ tính toán: std::prev(x.end()) một lần.

+3

Thành thật mà nói, tôi thậm chí không nghĩ đến sự cải tiến này. Nếu tôi đã cải thiện mã đó, tôi sẽ đi thẳng đến 'for (auto && x: drop_last (x))': các đặc tính hiệu suất giống nhau, không có khả năng đọc bị mất (ngược lại). –

+0

Có ai biết nếu có bất kỳ lợi ích hiệu suất nào với tối ưu hóa trình biên dịch (tức là '-O3' w/gcc) không? – user

+0

@ R.MartinhoFernandes +1 cho 'drop_last', mặc dù ứng dụng của tôi tốt hơn với' std :: prev (...) 'cho dải vòng lặp ở đây (trong mỗi vòng lặp lặp lại, tôi cần sử dụng' * iter' và (những gì tôi đoán là) '* std :: next (iter)'). – user

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