2016-02-15 21 views
6

Cho một vector, vc, ai có thể lặp qua các vector với một phạm vi cho:Có nên sử dụng một phạm vi cho vòng lặp thay vì các vòng lặp trên một véc-tơ không?

for (auto c : vc) 
    std::cout << c; 

Hoặc với một iterator:

for (auto it = vc.cbegin(); it != vc.cend(); ++it) 
    std::cout << *it; 

Có một lý do chức năng để sử dụng một phương pháp trong khác, hay đây chỉ là vấn đề về phong cách?

+4

lưu ý rằng khi bạn sử dụng 'tự động' trong vòng lặp dựa trên phạm vi, bạn sẽ nhận được * bản sao * của các phần tử vectơ, nếu đối tượng của bạn đắt tiền để sao chép, có thể mang lại các vấn đề về hiệu năng không mong muốn. Với việc sử dụng các trình vòng lặp, bạn lấy lại tham chiếu const, do đó các bản sao không xảy ra ở đây. Một cách để lấy lại tham chiếu const trong phạm vi dựa trên là 'for (const auto & c: vc) ...' –

Trả lời

4

Từ quan điểm hiệu suất, không có sự khác biệt nào. Như Bjarne Stroustrup viết trong cuốn sách của mình ngôn ngữ lập trình C++ Phiên bản thứ 4:

Vòng lặp đơn giản nhất là một phạm vi cho phép; nó chỉ đơn giản là cung cấp cho các lập trình viên truy cập vào mỗi phần tử của một phạm vi.

Là người hâm mộ nguyên tắc KISS, tôi có xu hướng thích cấu trúc đơn giản hơn các cấu trúc phức tạp hơn. Tuy nhiên, nó thực sự thích hợp với những gì bạn muốn đạt được. Từ cùng một cuốn sách, Bjarne tiết lộ lý do tại sao một vòng lặp phạm vi được thiết kế đơn giản:

Lưu ý rằng một dải vòng lặp là một cấu trúc đơn giản cố ý. Đối với ví dụ , sử dụng nó, bạn không thể chạm hai thành phần cùng một lúc và không thể di chuyển đồng thời hai dải ô một cách hiệu quả. Để làm được điều đó, chúng tôi cần một tuyên bố chung.

Do đó, có những ngữ cảnh mà bạn không thể sử dụng vòng lặp phạm vi và bạn phải nằm trong bảng sao kê cổ điển.

Vòng lặp phạm vi sử dụng dưới cùng khi có thể vì đơn giản hơn và dễ đọc hơn.

4

Nó ít nhiều là một vấn đề về phong cách, nhưng hãy xem xét nó theo cách này; phạm vi-cho vòng lặp ngắn gọn hơn sử dụng lặp lại rõ ràng. Bạn viết ít mã hơn, càng ít nơi mọi thứ có thể sai.

+1

Ngoài ra, nó dễ đọc hơn nhiều, vì nó ẩn các chi tiết thực hiện của vòng lặp. – emlai

+1

Phạm vi cho cũng có thể rõ ràng hơn cho trình biên dịch, cải thiện khả năng tối ưu hóa. – alcedine

+0

Điểm tốt. Tôi đồng ý. – JesseTG

2

Ví dụ cụ thể của bạn, chúng tương đương nhau. Và vì chúng tương đương nhau, bạn tự nhiên muốn thích phiên bản ngắn nhất xảy ra cũng ít bị lỗi nhất - miễn phí.

Phạm vi-cho vòng lặp cũng đã được đề xuất để được rút ngắn hơn nữa để:

for (var : range) 

nơi var sẽ có loại auto&& (aka forwading/tài liệu tham khảo phổ thông), đó là cách tốt nhất để có một tham chiếu đến một vật. Chỉ cần auto var sẽ tạo bản sao của từng phần tử, có thể không rẻ. Thật không may, nó đã không vượt qua.

Bạn thường không làm việc với trình vòng lặp trực tiếp vì vậy phạm vi-cho bạn nên là lựa chọn đầu tiên của bạn. Trình lặp lặp rõ ràng cũng có thể trỏ đến các phần tử nằm ngoài phạm vi vì bạn có thể tự do di chuyển trong phạm vi, dẫn đến hành vi không xác định.

1

Có hai sự khác biệt đáng kể giữa hai ví dụ của bạn. Trước tiên, auto c tạo bản sao của từng phần tử, do đó hãy sử dụng auto const& c nếu bạn không muốn tạo các bản sao không cần thiết. Thứ hai, phạm vi for được thực hiện theo các biến lặp không phải const, nhưng vòng lặp for của bạn sử dụng các trình lặp vòng lặp const.Điều đó không quan trọng nếu vc là một thùng chứa tiêu chuẩn, nhưng một số thùng chứa (ví dụ như trong Qt) thực hiện ngữ nghĩa sao chép trên ghi bằng cách sử dụng con trỏ chia sẻ nội bộ, trong trường hợp đó việc sử dụng trình lặp không phải const sẽ sao chép toàn bộ vùng chứa không cần thiết . Bạn có thể tránh điều này và vẫn sử dụng thoải mái nhiều for cú pháp bằng cách sử dụng C++ 17 std::as_const:

for (auto const& c : std::as_const(vc)) 
    std::cout << c; 

Bạn có thể dễ dàng thực hiện phiên bản của riêng bạn as_const nếu môi trường của bạn không cung cấp nó.

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