Jawaban:
Jika setidaknya ada 3 item dalam vektor, untuk menghapus 3 item terakhir adalah sederhana - cukup gunakan pop_back 3 kali:
#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';
}
Keluaran:
1 2
Ini adalah perilaku yang tidak ditentukan untuk meneruskan end()iterator ke parameter 1 yang erase()berlebihan. Bahkan jika tidak, erase()membatalkan iterator yang "pada dan setelah" elemen yang ditentukan, membuat dtidak valid setelah iterasi loop pertama.
std::vectormemiliki erase()kelebihan 2-parameter yang menerima serangkaian elemen untuk dihapus. Anda tidak memerlukan loop manual sama sekali:
if (X.size() >= 3)
X.erase(X.end()-3, X.end());
Pertama, X.end()tidak mengembalikan iterator ke elemen terakhir vektor, melainkan mengembalikan iterator ke elemen melewati elemen terakhir dari vektor, yang merupakan elemen yang sebenarnya tidak dimiliki vektor, itu sebabnya ketika Anda mencoba untuk hapus dengan X.erase(d)crash program.
Alih-alih, asalkan vektor mengandung setidaknya 3 elemen, Anda dapat melakukan hal berikut:
X.erase( X.end() - 3, X.end() );
Yang sebaliknya pergi ke elemen terakhir ketiga, dan menghapus setiap elemen setelah itu sampai tiba X.end().
EDIT: Hanya untuk memperjelas, X.end()adalah LegacyRandomAccessIterator yang ditentukan untuk memiliki -operasi yang valid yang mengembalikan LegacyRandomAccessIterator lain .
Definisi end()dari cppreference adalah:
Mengembalikan iterator yang merujuk ke elemen past-the-end dalam wadah vektor.
dan sedikit di bawah:
Itu tidak menunjuk ke elemen apa pun, dan dengan demikian tidak akan dereferensi.
Dengan kata lain, vektor tidak memiliki elemen yang diakhiri () menunjuk ke. Dengan mendereferensi non-elemen melalui metode erase (), Anda mungkin mengubah memori yang bukan milik vektor. Karenanya hal-hal buruk dapat terjadi sejak saat itu.
Ini adalah konvensi C ++ biasa untuk menggambarkan interval sebagai [rendah, tinggi), dengan nilai "rendah" termasuk dalam interval, dan nilai "tinggi" dikeluarkan dari interval.
Anda bisa menggunakan 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;
}
Ada beberapa hal yang perlu disebutkan:
reverse_iterator ritdimulai pada elemen terakhir dari vector X. Posisi ini disebut rbegin.erasemembutuhkan klasik iteratoruntuk bekerja dengannya. Kami mendapatkannya dari ritmenelepon base. Tapi iterator baru itu akan menunjuk ke elemen berikutnya dari ritarah maju.ritsebelum menelepon basedaneraseJuga jika Anda ingin tahu lebih banyak tentang reverse_iterator, saya sarankan mengunjungi jawaban ini .
Sebuah komentar (sekarang dihapus) dalam pertanyaan menyatakan bahwa "tidak ada - operator untuk iterator." Namun, kode berikut ini mengkompilasi dan berfungsi di keduanya MSVCdan clang-cl, dengan standar yang ditetapkan baik C++17atau 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;
}
Definisi yang disediakan untuk operator-adalah sebagai berikut (di <vector>header):
_NODISCARD _Vector_iterator operator-(const difference_type _Off) const {
_Vector_iterator _Tmp = *this;
return _Tmp -= _Off;
}
Namun, saya jelas bukan pengacara bahasa C ++, dan mungkin saja ini adalah salah satu ekstensi Microsoft yang 'berbahaya'. Saya akan sangat tertarik untuk mengetahui apakah ini bekerja pada platform / kompiler lain.
-didefinisikan untuk tipe iterator tersebut.
operator-definisi untuk iterator, Anda bisa menggunakan std::advance()atau std::prev()sebaliknya.
Pernyataan ini
if (i == 1) X.erase(d);
memiliki perilaku yang tidak terdefinisi.
Dan pernyataan ini mencoba untuk menghapus hanya elemen sebelum elemen terakhir
else X.erase(d - i);
karena Anda memiliki satu lingkaran dengan hanya dua iterasi
for (size_t i = 1; i < 3; i++) {
Anda perlu sesuatu seperti yang berikut ini.
#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;
}
Output program adalah
1 2
dtidak benar-benar ada. Ini adalah nilai kenari satu masa lalu yang hanya dapat digunakan untuk menemukan bagian akhirvector. Anda tidak bisa menghapusnya. Selanjutnya, segera setelah Anda menghapus iterator, itu hilang. Anda tidak dapat menggunakannya dengan aman sesudahnya untuk apa pun, termasukd - i.