2010-11-04 28 views
5

tôi thấy đoạn mã sau dùng để xóa một phần tử được chọn từ std::vector:Nhà điều hành + trình hỗ trợ lặp không?

vector<hgCoord>::iterator it; 
int iIndex = 0; 
    const int iSelected = 5; 
for(it = vecPoints.begin(); it != vecPoints.end(); ++it, ++iIndex) 
{ 
    if(iIndex == iSelected) 
    { 
     vecPoints.erase(it); 
     break; 
    } 
} 

Tôi cho rằng mã này là không hiệu quả và nên được viết như sau:

vector<hgCoord>::iterator it; 
int iIndex = 0; 
    const int iSelected = 5; // we assume the vector has more than 5 elements. 

    vecPoints.erase(vecPoints.begin() + iSelected); 

Tuy nhiên, tôi không chắc chắn liệu mã này có tuân thủ tiêu chuẩn C++ STL hay không.

+0

Bạn là chính xác, vì 'std :: vector :: iterator' là một' RandomAccessIterator' (a.k.a. 'T *'). Chỉ cần nhớ rằng nếu bạn có ít hơn 5 phần tử trong vectơ của mình, thuật toán thứ hai của bạn sẽ thất bại. –

+1

Nếu những tiền tố đó là một dạng ký hiệu tiếng Hungari, tôi mạnh mẽ phản đối một trong hai đoạn mã. –

+0

@ eq-: cái gì, vì 'i' nên được sử dụng làm tiền tố có nghĩa là' trình lặp', ý của bạn là ;-p –

Trả lời

12

Để làm cho mã này chung chung, do nó hoạt động bất kể các iterator hỗ trợ operator +, và sử dụng các ứng dụng sẵn có hiệu quả nhất:

template <typename C> 
void erase_at(C& container, typename C::size_type index) { 
    typename C::iterator i = container.begin(); 
    std::advance(i, index); 
    container.erase(i); 
} 

Bên trong, std::advance sử dụng operator + nếu loại iterator hỗ trợ nó. Nếu không (ví dụ: đối với std::list<>::iterator), nó sẽ tiến hành một bước lặp tại một thời điểm trong một vòng lặp, giống như mã đầu tiên bạn đã đăng.

+0

......... yup ..... +1 –

+3

Để trả lời nhận xét về câu trả lời đã xóa của dirbeas - tôi nghĩ lý do 'std :: advance' thay đổi đối số của nó là điều gì đó liên quan đến thực tế bởi vì nó rất kiểu bất khả tri, đặc biệt nó hoạt động trên tất cả các InputIterator, * rẻ * nhưng * nguy hiểm * để sao chép. Khi được sử dụng với một iterator có thể chỉ là một InputIterator, không phải là một ForwardIterator, bạn không thể sử dụng một cách an toàn giá trị cũ một lần nữa, vì vậy ngay cả khi nó đã trả về một iterator, bạn vẫn sẽ chỉ sử dụng nó như 'i = std :: tạm ứng (i, n), ', hoặc tạm thời như trong mã của dribeas '. Trả về 'void' giúp ngăn chặn ngu xuẩn. Đôi khi. Có lẽ. –

+0

Cảm ơn bạn đã giải thích này. – q0987

10

Trình vòng lặp truy cập ngẫu nhiên hỗ trợ cộng và trừ, và các trình vòng lặp std::vector là truy cập ngẫu nhiên.

2

Bạn tranh luận một cách chính xác :)

1

Điều đó sẽ làm việc tốt cho một vector vì lặp vector là lặp truy cập ngẫu nhiên, do đó, nó OK để thêm một bù đắp như bạn đã làm. Điều tương tự cũng không hiệu quả đối với một số loại container khác (chẳng hạn như deque hoặc map).

Vì vậy, mã của bạn tốt hơn cho một véc tơ, nhưng mã khác có thể được dự định làm việc với các loại vùng chứa khác.

+0

Thực ra, 'deque' cũng sử dụng các trình vòng lặp truy cập ngẫu nhiên. –

+0

Tôi nghĩ rằng mã sửa đổi hoạt động cho vector, chuỗi và deque. – q0987

+0

@Fred Larson: Rất tiếc! Tôi không biết tại sao tôi gõ deque, tôi có nghĩa là danh sách! Cảm ơn vì sự đúng đắn của bạn. – dajames