C ++ STL vectơ: Lấy iterator từ chỉ mục?


200

Vì vậy, tôi đã viết một loạt mã truy cập các phần tử trong một vectơ stl theo chỉ mục [], nhưng bây giờ tôi cần sao chép chỉ một đoạn của vectơ. Có vẻ như vector.insert(pos, first, last)là chức năng tôi muốn ... ngoại trừ tôi chỉ có đầu tiên và cuối cùng là ints. Có cách nào hay để tôi có được một trình vòng lặp cho các giá trị này không?



Nếu tôi không sai, không có câu trả lời nào kiểm tra giới hạn, đây có thể là một vấn đề. Cụ thể, std :: trước tài liệu nói rằng hành vi không được xác định nếu bạn sử dụng nó để vượt qua giới hạn vùng chứa bên dưới.
Martin Pecka

Câu trả lời:


293

Thử cái này:

vector<Type>::iterator nth = v.begin() + index;

4
Nói chung, bạn có thể sử dụng cùng số học với các trình lặp STL hơn với các con trỏ. Chúng được thiết kế để có thể trao đổi khi sử dụng thuật toán STL.
Vincent Robert

18
@VincentRobert: Cách khác. Con trỏ là các triển khai hợp lệ của các trình lặp ngẫu nhiên STL, loại mạnh nhất. Nhưng các loại khác, ít mạnh hơn như các bộ lặp tiến không hỗ trợ cùng số học.
MSalters

6
Tôi muốn thêm năm xu của mình vào câu trả lời này và đề nghịstd::next(v.begin(), index)
stryku

87

cách được đề cập bởi @dirkgently ( v.begin() + index )đẹp và nhanh cho vectơ

nhưng cách chung nhất và cho các trình lặp truy cập ngẫu nhiên cũng hoạt động theo thời gian không đổi. std::advance( v.begin(), index )

Sự
khác biệt EDIT trong cách sử dụng:

std::vector<>::iterator it = ( v.begin() + index );

hoặc là

std::vector<>::iterator it = v.begin();
std::advance( it, index );

được thêm vào sau ghi chú @litb.


không std :: trước yêu cầu một trình lặp không phải là hằng số làm đối số đầu tiên?
goldPseudo

bạn có thể sử dụng std ::
advanced

1
bạn không nên tin tưởng msvc về vấn đề đó. nó có một phần mở rộng không chuẩn khiến nó chấp nhận loại điều này, tuy nhiên tất cả các trình biên dịch khác hoạt động theo tiêu chuẩn và từ chối nó.
Julian Schaub - litb

1
Tôi nghĩ rằng vấn đề là sự nhầm lẫn về ý nghĩa của "const": advanced () sẽ vui vẻ hoạt động trên const_iterator <T>, đây là một trình vòng lặp có thể thay đổi đề cập đến một phần tử const của loại T; nó sẽ không hoạt động trên một đối tượng iterator mà chính nó là const (tức là "const iterator <T>" hoặc "iterator <T> const").
j_random_hacker

7
Nếu bạn biết rằng bạn đang làm việc với một std::vector, không có điểm nào trong việc sử dụng std::advance. Nó chỉ khiến bạn nghĩ rằng bạn đang viết mã không xác định container (mà bạn không nghĩ đến các quy tắc vô hiệu hóa vòng lặp, độ phức tạp thời gian chạy khác nhau và không có gì). Trường hợp duy nhất có std::advanceý nghĩa là khi bạn tự viết một mẫu mà không biết nó đang xử lý loại trình lặp nào.
Frerich Raabe

47

Cũng thế; auto it = std::next(v.begin(), index);

Cập nhật: Cần một trình biên dịch tuân thủ C ++ 11x


2
Cần lưu ý rằng đây là cách C ++ 11! std :: next tương đương với std :: trước. Sử dụng các chức năng này thay vì sử dụng arithologists làm cho việc hoán đổi các loại container dễ dàng hơn rất nhiều. Thậm chí hoạt động trên các mảng c afaik, giống như std :: started và std :: end.
Trình phóng to

2
Cũng cần lưu ý rằng std :: advanced được thiết kế bởi một thằng ngốc vì nó sử dụng một tham chiếu làm đầu ra, chứ không phải giá trị trả về.
Viktor Sehr

1
for (auto it = started (c); it! = end (c); Advance (it, n)) {...}
Trình phóng to

2
Cả hai đều có công dụng của chúng. stda :: advanced rất hữu ích cho việc thay đổi iterator tại chỗ. Đó là một mối quan tâm hiệu suất trong các vòng lặp. Tôi muốn tiếp theo trong trường hợp chuyển nhượng, như bạn đề xuất. Tôi chỉ thấy nó hơi khắc nghiệt khi tuyên bố nó là ngu ngốc. Cả hai chức năng được thiết kế với các tình huống khác nhau, mặc dù về cơ bản chúng giống nhau.
Công cụ phóng to

5
@Zoomulator: Nếu sao chép trình lặp của bạn là mối quan tâm về hiệu suất, bạn có vấn đề lớn hơn để giải quyết.
Vịt Mooing


-3

Thực tế std :: vector có nghĩa là được sử dụng như tab C khi cần thiết. (Theo yêu cầu tiêu chuẩn của C ++, theo như tôi biết - thay thế cho mảng trong Wikipedia ) Chẳng hạn, việc làm theo cách này là hoàn toàn hợp pháp, theo tôi:

int main()
{

void foo(const char *);

sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');

foo(&vec[0]);
}

Tất nhiên, foo không được sao chép địa chỉ được truyền dưới dạng tham số và lưu trữ ở đâu đó hoặc bạn nên đảm bảo trong chương trình của mình không bao giờ đẩy bất kỳ mục mới nào trong vec hoặc yêu cầu thay đổi dung lượng. Hoặc lỗi phân khúc rủi ro ...

Do đó, trong ví dụ của bạn, nó dẫn đến

vector.insert(pos, &vec[first_index], &vec[last_index]);

Làm cho tôi tự hỏi tại sao họ quyết định trừu tượng hóa với các trình vòng lặp nếu chúng chỉ là con trỏ ... về cơ bản chúng là "che giấu" các khả năng này.
mở

Vì sự đồng thuận? Vì nó sẽ cho phép bạn dễ dàng loại bỏ cá thể vectơ cho bất kỳ loại container nào khác trong mã của bạn.
yves Baume

4
& vec [i] mang lại một con trỏ không nhất thiết phải tương thích với vectơ <> :: iterator. vec.begin () + tôi vẫn có lợi ích là bất kỳ trình lặp nào mà thư viện của bạn định nghĩa nó - ví dụ như bao gồm các trình vòng lặp được kiểm tra trong chế độ gỡ lỗi. Vì vậy, nếu bạn không cần một con trỏ (ví dụ I / O), bạn nên luôn thích các trình vòng lặp.
sellibitze

@KerrekSB Từ 23.3.6.1 trong dự thảo tiêu chuẩn c ++: "Các phần tử của vectơ được lưu trữ liên tục, có nghĩa là nếu v là vectơ <T, Allocator> trong đó T là một loại khác với bool, thì nó tuân theo danh tính & v [ n] == & v [0] + n cho tất cả 0 <= n <v.size () "
yves Baume

2
@yvesBaume: không liên quan gì đến các trình vòng lặp vector. Tuy nhiên, đúng là con trỏ thường cũng lặp - họ chỉ không vector vòng lặp.
Kerrek SB
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.