2013-06-05 28 views
15

Liệu các C++ biên dịch chăm sóc các trường hợp như thế, các tòa nhà là véc tơ:Có tốn kém khi tính toán kích thước vectơ cho các vòng lặp, mỗi lần lặp không?

for (int i = 0; i < buildings.size(); i++) {} 

có nghĩa là, nó nhận thấy nếu các tòa nhà được sửa đổi trong vòng lặp hay không, và sau đó dựa trên mà không đánh giá nó mỗi lần lặp ? Hoặc có lẽ tôi nên làm điều này bản thân mình, không phải là đẹp, nhưng:

int n = buildings.size(); 
for (int i = 0; i < n; i++) {} 
+2

Đây là một chi phí nhỏ như vậy (nếu có) mà nó hoàn toàn không đáng lo ngại. – Anycorn

+2

* "không phải là đẹp nhưng" * - Vâng, 'cho (int i = 0, n = buildings.size(); i

+0

Hoặc 'cho (int i = buildings.size() - 1; i> = 0; i -)' – Izkata

Trả lời

12

buildings.size() có khả năng sẽ được inlined bởi trình biên dịch để truy cập trực tiếp các lĩnh vực kích thước riêng trên lớp vector<T>. Vì vậy, bạn không nên tách cuộc gọi đến size. Loại tối ưu hóa vi mô này là thứ mà bạn không muốn lo lắng (trừ khi bạn đang ở trong một số vòng lặp thực sự chặt chẽ được xác định là nút cổ chai bằng cách lược tả).

+1

Trong nhiều lần triển khai, 'size()' thực sự phải trừ hai thành viên của con trỏ. Mà vẫn còn rất rẻ. – aschepler

+0

@aschepler Điểm tốt. - Đây là lý do tại sao tôi nói "* có khả năng ... truy cập vào trường riêng *." :) –

+0

isnt rằng lĩnh vực kỹ thuật? – NoSenseEtAl

7

Đừng quyết định xem nên đi một hay khác bằng cách suy nghĩ về mặt hiệu suất; trình biên dịch của bạn có thể hoặc không thể nội tuyến cuộc gọi - và std::vector::size() có sự phức tạp liên tục, quá.

Điều bạn nên xem xét là chính xác, vì hai phiên bản sẽ hoạt động rất khác nếu bạn thêm hoặc xóa các phần tử trong khi lặp lại.

Nếu bạn không sửa đổi véc tơ theo bất kỳ cách nào trong vòng lặp, hãy liên kết với phiên bản cũ để tránh một chút trạng thái (biến số n).

+0

Vì vậy, bạn đề nghị tôi đi cho các tùy chọn đơn giản đầu tiên, không có vấn đề nếu tôi sửa đổi kích thước vector hay không? – user2381422

+0

Tôi lấy lại điều đó: Bảng 65: "Những mục nhập được đánh dấu‘ ‘(Ghi chú A)’ ’phải có độ phức tạp liên tục”. 'size()' được đánh dấu "Note A" Tuy nhiên, "nên" là một chút lung lay ở đây. –

+0

@ user2381422: Bạn sẽ sử dụng phiên bản thứ hai nếu bạn đã thêm các phần tử vào vectơ khi bạn lặp lại, nhưng bạn chỉ muốn lặp lại đến phần cuối của vectơ. –

0

Chỉ bắt đầu tự tối ưu hóa nội dung như vậy, nếu đó thực sự là vấn đề hiệu suất. Sau đó đo sự khác biệt. Nếu không, bạn sẽ rất nhiều mã xấu xí khó có thể gỡ lỗi và ít hiệu quả hơn để làm việc. Hầu hết các trình biên dịch hàng đầu có lẽ sẽ tối ưu hóa nó đi, nếu kích thước không thay đổi trong vòng lặp.

Nhưng ngay cả khi nó không được tối ưu hóa, có thể nó sẽ được gạch chân (vì các mẫu được gạch chân theo mặc định) và hầu như không có chi phí.

1

Giả sử hàm size() là hàm nội tuyến cho mẫu cơ sở, bạn cũng có thể giả định rằng nó rất ít chi phí. Nó khác xa, ví dụ: strlen() trong C, có thể có chi phí chính. Có thể vẫn sử dụng nhanh hơn int n = buildings.size(); - bởi vì trình biên dịch có thể thấy rằng n không thay đổi bên trong vòng lặp, vì vậy hãy tải nó vào sổ đăng ký và không gián tiếp tìm nạp kích thước vectơ. Nhưng nó rất nhỏ, và chỉ những vòng lặp được tối ưu hóa rất chặt chẽ mới cần được điều trị này (và chỉ sau khi phân tích và thấy rằng đó là một lợi ích), vì nó không luôn luôn hoạt động tốt như bạn mong đợi.

2

Nếu trình biên dịch có thể xác định rằng buildings không bị đột biến trong vòng lặp (ví dụ nếu đó là vòng lặp đơn giản không có cuộc gọi hàm có thể có phản ứng phụ), nó có thể sẽ loại bỏ tính toán. Nhưng tính toán kích thước của một vector là một phép trừ duy nhất dù sao cũng nên khá rẻ.

Viết mã theo cách hiển nhiên (size bên trong vòng lặp) và chỉ khi lược tả cho bạn thấy rằng quá chậm nên bạn xem xét một cơ chế thay thế.

2

tôi viết vòng như thế này:

for (int i = 0, maxI = buildings.size(); i < maxI; ++i) 

Đưa sóc nhiều vấn đề cùng một lúc: đề nghị tối đa là cố định lên phía trước, không còn phải suy nghĩ về hiệu suất bị mất, củng cố các loại. Nếu đánh giá là ở giữa biểu thức nó cho thấy vòng lặp thay đổi kích thước bộ sưu tập.

Ngôn ngữ quá xấu không cho phép sử dụng hợp lý const, nếu không nó sẽ là const maxI.

OTOH cho nhiều trường hợp hơn và nhiều hơn nữa tôi thay vì sử dụng một số algo, lambda thậm chí cho phép làm cho nó trông gần giống như mã truyền thống.

+0

Có lẽ 'std :: size_t' sẽ là một giá trị mặc định tốt hơn' int' cho một chỉ mục. – GManNickG

+0

@GManNickG: 'size_t' chắc chắn sẽ tốt hơn; nếu bạn muốn thực sự hiểu về nó, bạn sẽ sử dụng 'std :: vector :: size_type' vì đó là kiểu' size() 'trả về. –

+0

Tôi đang ở với trại "mặc định để int", nơi tôi biết từ thiết kế mà phạm vi của int là okay, tôi sử dụng int. Nhưng hãy sử dụng cùng một thứ với size_t. Trong cách sử dụng thông thường khác, nó là 'auto' và inited với' .cbegin() 'hoặc' begin() '. –

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