Câu trả lời:
Nếu có ít nhất 3 mục trong vectơ, để xóa 3 mục cuối rất đơn giản - chỉ cần sử dụng pop_back 3 lần:
#include <vector>
#include <iostream>
int main()
{
std::vector<float> v = { 1, 2, 3, 4, 5 };
for (int i = 0; i < 3 && !v.empty(); ++i)
v.pop_back();
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
}
Đầu ra:
1 2
Đó là hành vi không xác định để chuyển end()
iterator đến erase()
quá tải 1 tham số . Ngay cả khi nó không, erase()
vô hiệu hóa các trình vòng lặp là "tại và sau" phần tử đã chỉ định, làm cho d
không hợp lệ sau lần lặp vòng 1.
std::vector
có erase()
quá tải 2 tham số chấp nhận một loạt các yếu tố cần loại bỏ. Bạn không cần một vòng lặp thủ công nào cả:
if (X.size() >= 3)
X.erase(X.end()-3, X.end());
Đầu tiên, X.end()
không trả lại một iterator cho phần tử cuối cùng của vectơ, nó trả về một iterator cho phần tử qua phần tử cuối cùng của vectơ, đó là một phần tử mà vectơ không thực sự sở hữu, đó là lý do tại sao khi bạn cố gắng xóa nó với X.erase(d)
sự cố chương trình.
Thay vào đó, với điều kiện là vectơ chứa ít nhất 3 phần tử, bạn có thể thực hiện các thao tác sau:
X.erase( X.end() - 3, X.end() );
Mà thay vào đó đi đến phần tử cuối cùng thứ ba, và xóa mọi phần tử sau đó cho đến khi nó đến X.end()
.
EDIT: Chỉ cần làm rõ, X.end()
là một LegacyRandomAccessIterator được chỉ định để có một -
hoạt động hợp lệ trả về một LegacyRandomAccessIterator khác .
Định nghĩa của end()
từ cppreference là:
Trả về một trình vòng lặp tham chiếu đến phần tử quá khứ trong vùng chứa vector.
và hơi bên dưới:
Nó không trỏ đến bất kỳ yếu tố nào, và do đó sẽ không bị hủy bỏ.
Nói cách khác, vectơ không có phần tử nào kết thúc () trỏ đến. Bằng cách thông báo rằng phần tử không phải là phần tử thông qua phương thức erase (), bạn có thể thay đổi bộ nhớ không thuộc về vectơ. Do đó những điều xấu xí có thể xảy ra từ đó.
Đó là quy ước C ++ thông thường để mô tả các khoảng là [thấp, cao), với giá trị thấp thấp của Hồi giáo được bao gồm trong khoảng đó và giá trị High cao của Hồi giáo được loại trừ khỏi khoảng đó.
Bạn có thể sử dụng một reverse_iterator
:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<float> X = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6};
// start the iterator at the last element
vector<float>::reverse_iterator rit = X.rbegin();
// repeat 3 times
for(size_t i = 0; i < 3; i++)
{
rit++;
X.erase(rit.base());
}
// display all elements in vector X
for(float &e: X)
cout << e << '\n';
return 0;
}
Có vài điều cần đề cập:
reverse_iterator rit
bắt đầu từ phần tử cuối cùng của vector X
. Vị trí này được gọi rbegin
.erase
đòi hỏi cổ điển iterator
để làm việc với. Chúng tôi nhận được điều đó từ rit
bằng cách gọi base
. Nhưng trình vòng lặp mới đó sẽ trỏ đến phần tử tiếp theo từ rit
hướng thuận.rit
trước khi gọi base
vàerase
Ngoài ra nếu bạn muốn biết thêm về reverse_iterator
, tôi khuyên bạn nên truy cập câu trả lời này .
Một nhận xét (hiện đã bị xóa) trong câu hỏi nói rằng "không có toán tử cho trình lặp." Tuy nhiên, đoạn mã sau sẽ biên dịch và hoạt động ở cả hai MSVC
và clang-cl
, với tiêu chuẩn được đặt thành C++17
hoặc C++14
:
#include <iostream>
#include <vector>
int main()
{
std::vector<float> X{ 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f };
for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
std::vector<float>::iterator d = X.end();
X.erase(d - 3, d); // This strongly suggest that there IS a "-" operator for a vector iterator!
for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
return 0;
}
Định nghĩa được cung cấp cho operator-
như sau (trong <vector>
tiêu đề):
_NODISCARD _Vector_iterator operator-(const difference_type _Off) const {
_Vector_iterator _Tmp = *this;
return _Tmp -= _Off;
}
Tuy nhiên, tôi chắc chắn không có luật sư ngôn ngữ C ++ và có thể đây là một trong những tiện ích mở rộng 'nguy hiểm' của Microsoft. Tôi sẽ rất quan tâm để biết nếu điều này hoạt động trên các nền tảng / trình biên dịch khác.
-
được xác định cho các loại trình vòng lặp đó.
operator-
định nghĩa cho các trình vòng lặp, bạn chỉ có thể sử dụng std::advance()
hoặc std::prev()
thay vào đó.
Tuyên bố này
if (i == 1) X.erase(d);
có hành vi không xác định.
Và tuyên bố này cố gắng chỉ loại bỏ phần tử trước phần tử cuối cùng
else X.erase(d - i);
bởi vì bạn có một vòng lặp chỉ với hai lần lặp
for (size_t i = 1; i < 3; i++) {
Bạn cần một cái gì đó như sau.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<float> v = { 1, 2, 3, 4, 5 };
auto n = std::min<decltype( v.size() )>( v.size(), 3 );
if ( n ) v.erase( std::prev( std::end( v ), n ), std::end( v ) );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
Đầu ra của chương trình là
1 2
d
không thực sự tồn tại. Đó là giá trị hoàng yến một đầu chỉ có thể sử dụng để tìm ra kết thúc củavector
. Bạn không thể loại bỏ nó. Tiếp theo, ngay khi bạn xóa một trình vòng lặp, nó sẽ biến mất. Sau đó, bạn không thể sử dụng nó một cách an toàn cho mọi thứ, kể cảd - i
.