2010-09-28 26 views
11

Vì vậy, khi chúng ta cần phải đi qua một container từ đầu đến cuối, chúng tôi viết một cái gì đó giống nhưLàm cách nào để kết thúc() được triển khai trong các vùng chứa STL?

for (i = v->begin(); i != v->end(); i++)

giả i là một iterator cho container v.

Câu hỏi của tôi là "điều gì đảm bảo rằng kết thúc sẽ luôn trỏ đến một phần tử cuối cùng trong vùng chứa?" STL đảm bảo hành vi này như thế nào và có khả năng là trường hợp này không đúng không?

+4

STL không đảm bảo hành vi này. STL ** thực hiện ** hành vi này dựa trên các yêu cầu được xác định bởi tiêu chuẩn. Tiêu chuẩn nói đây là cách nó được cho là làm việc với nhà phát triển thực hiện STL sau đó được yêu cầu làm cho STL hoạt động chính xác. –

+5

Đó không phải là cách thực hành tốt nhất. Ưu tiên toán tử tăng trướC++ i thay vì i ++ khi bạn không lưu trữ giá trị. Đối với nhiều loại, nó nhanh hơn. –

+0

@Jive Dadson: đó không phải là mối quan tâm chính của tôi -> recomputing 'v-> end()' ở mỗi lượt của vòng lặp chắc chắn là kém hiệu quả ... 'cho (auto it = v.begin(), end = v .end(); it! = end; ++ it) 'là dạng kinh điển, mặc dù trong C++ 0x ta cũng có thể dùng' for (auto val: v) 'hoặc' std :: foreach' và lambda chức năng. –

Trả lời

3

Thông số kỹ thuật stl đảm bảo rằng kết thúc sẽ là một trong quá khứ kết thúc See here. Đó sẽ luôn là trường hợp. Chính xác như thế nào nó thực hiện điều này có thể phụ thuộc vào việc thực hiện (đôi khi các giá trị chỉ được thiết lập để null chẳng hạn), nhưng yên tâm vòng lặp của bạn sẽ được OK miễn là v là một con trỏ hợp lệ.

1

"kết thúc sẽ luôn trỏ đến một phần tử cuối cùng trong vùng chứa" có nghĩa là nếu bạn tăng trình vòng lặp trỏ đến phần tử cuối cùng, nó sẽ bằng kết quả của end(). Việc triển khai có thể khác nhau. Trong Visual C++ std::vector::end() trả về trình lặp thực hiện cụ thể mà giữ con trỏ bằng không.

+2

Tôi thực sự nghi ngờ điều đó, vì 'std :: vector :: iterator' là một trình vòng lặp truy cập ngẫu nhiên. Nếu 'std :: vector :: end()' trả về '(T *) 0',' end() - begin() 'sẽ là bất hợp pháp, nhưng nó cần trả về' std :: vector :: size() ' – MSalters

+1

Để chính xác hơn:' end' trả về một trình lặp cụ thể thực hiện mà giữ con trỏ 0. –

+1

Phần * giữ con trỏ zero * là, tốt, không cần thiết và không chính xác. Trong việc thực hiện vector gcc, 'vector <> :: end()' được định nghĩa là 'vector <> :: begin() + vector <> :: size()', và thực sự được lưu trữ trong đối tượng 'vector <>' (Vector GCC được thực hiện bằng ba con trỏ: * bắt đầu *, * kết thúc * và * end_of_capacity *, trong đó 'begin == end' nếu vectơ trống,' begin + size() == end' mọi lúc và 'end == end_of_capacity' nếu' size() == capacity() 'Không có * con trỏ zero * ở bất cứ nơi nào để xem. –

3

C++ 03 Mục 23.1/7 nói

bắt đầu() trả về một iterator đề cập đến phần tử đầu tiên trong thùng sơn.

end() trả về một trình lặp là giá trị giá trị cuối cùng cho vùng chứa.

Nếu vùng chứa trống, thì begin() == end();

+0

Đây có phải là lý do slist không chính thức STL? cuối() của slist là 0 – vrdhn

21

STL đảm bảo hành vi này bằng cách luôn luôn lưu trữ những thứ như thế này:

vector

Trong cuối (chơi chữ), nó không có vấn đề gì end(), miễn là nó luôn luôn end() (và, rõ ràng, không thể nhầm lẫn với bất kỳ nút nào khác).

+13

Mate, bạn nhận được 1 chỉ cho đồ họa sôi nổi:) – paxdiablo

+1

Sơn FTW, tôi muốn nói :) –

+0

Không trích dẫn dưới đây từ tiêu chuẩn C++ làm mất hiệu lực câu trả lời này? đặc biệt là đồ họa. – yasouser

1

Bạn đang hỏi về tất cả các hộp chứa STL ... không phải là từ đề cập đến vector cụ thể khi kết thúc() có thể được triển khai như bạn mong đợi một cách trực giác. Ai là người cuối cùng trong một std :: map <>? Điều "kết thúc là một trong những nút được sử dụng cuối cùng" chỉ là một khái niệm logic, thể hiện rằng bạn có thể tăng một cách an toàn từ nút được sử dụng lần cuối, phân biệt/đánh giá nó từ/đến khái niệm trừu tượng về "kết thúc" và thực hiện một số nút số học mà kết thúc được coi là một hơn nữa so với nút được sử dụng cuối cùng. Đừng mang nó theo nghĩa đen.

0

Như một số áp phích trước đã nêu end() là một phần tử kết thúc. Nếu bạn cần truy cập phần tử cuối cùng thông qua trình lặp sử dụng iter = container.end() - 1; Nếu không, trong trường hợp của vectơ, variable = someVector.back(); Giả sử biến đó thuộc kiểu dữ liệu someVector chứa.

Đối với những gì đảm bảo rằng nó trỏ đến cùng, chính hộp chứa sẽ xử lý nội bộ.Bạn chỉ cần đối xử với nó như một hộp đen giống như bất kỳ đối tượng khác và tin tưởng nó làm điều đó một cách chính xác.

Bất cứ khi nào vùng chứa được thay đổi kích thước, nó sẽ theo dõi nơi kết thúc và sẽ được cập nhật trước khi bạn truy cập lại end(). Tùy thuộc vào thùng chứa tuy nhiên, nếu bạn có một trình lặp và thay đổi nó theo một số cách, nó có thể làm mất hiệu lực trình lặp và phá vỡ quá trình lặp của bạn.

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