Відповіді:
Якщо у векторі принаймні 3 елементи, видалити останні 3 елементи просто - просто використовуйте pop_back 3 рази:
#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';
}
Вихід:
1 2
Не визначена поведінка передати end()ітератор на 1-параметричне erase()перевантаження. Навіть якщо цього не було, erase()недійсні ітератори, які є "під і після", вказаного елемента, роблячи dнедійсними після ітерації 1-го циклу.
std::vectorмає 2-параметричне erase()перевантаження, яке приймає низку елементів для видалення. Ручний цикл вам взагалі не потрібен:
if (X.size() >= 3)
X.erase(X.end()-3, X.end());
По-перше, X.end()не повертає ітератор до останнього елемента вектора, він швидше повертає ітератор до елемента, що минає останній елемент вектора, який є елементом, яким власне вектор не володіє, тому, коли ви намагаєтеся видалити його при X.erase(d)збоях програми.
Натомість за умови, що вектор містить щонайменше 3 елементи, ви можете зробити наступне:
X.erase( X.end() - 3, X.end() );
Що замість цього переходить до третього останнього елемента і стирає кожен елемент після цього, поки не потрапить X.end().
EDIT: Просто для уточнення, X.end()це LegacyRandomAccessIterator, який вказано, щоб мати дійсну -операцію, яка повертає інший LegacyRandomAccessIterator .
Визначення end()від cppreference :
Повертає ітератор, що посилається на останній елемент в векторному контейнері.
і трохи нижче:
Він не вказує на будь-який елемент і, таким чином, не може бути відмежований.
Іншими словами, вектор не має елемента, на який вказує кінець (). За разименованія , що НЕ-елемент через метод стирання (), ви , можливо , змінюючи пам'ять , яка не належить до вектору. Звідси можуть відбуватися потворні речі.
Це звичайна умова C ++ для опису інтервалів як [низький, високий], із значенням "низьке", включеним у інтервал, а значення "високе" виключене з інтервалу.
Ви можете використовувати 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;
}
Можна згадати кілька речей:
reverse_iterator ritпочинається з останнього елемента vector X. Ця позиція називається rbegin.eraseвимагає класичної iteratorроботи. Ми отримуємо це rit, зателефонувавши base. Але цей новий ітератор буде вказувати на наступний елемент з ritпрямого напрямку.ritперед тим, як дзвонити baseіeraseТакож якщо ви хочете дізнатися більше про це reverse_iterator, пропоную відвідати цю відповідь .
У коментарі (зараз видалено) у запитанні було зазначено, що "немає - оператора для ітератора". Тим НЕ менше, наступний код компілюється і працює в обох MSVCі clang-cl, зі стандартним набором або C++17або 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;
}
Визначення, яке надається для operator-, таке (у <vector>заголовку):
_NODISCARD _Vector_iterator operator-(const difference_type _Off) const {
_Vector_iterator _Tmp = *this;
return _Tmp -= _Off;
}
Однак я, безумовно, не є юристом на мові C ++, і можливо, що це одне з тих "небезпечних" розширень Microsoft. Мені б дуже цікаво дізнатися, чи працює це на інших платформах / компіляторах.
-визначені для цих типів ітераторів.
operator-визначено ітераторів, ви можете просто використовувати std::advance()або std::prev()замість цього.
Це твердження
if (i == 1) X.erase(d);
має невизначену поведінку.
І це твердження намагається видалити лише елемент перед останнім елементом
else X.erase(d - i);
тому що у вас є цикл із лише двома ітераціями
for (size_t i = 1; i < 3; i++) {
Вам потрібно щось подібне.
#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;
}
Вихід програми є
1 2
dнасправді не існує. Це значення "канарного каналу", що минуло в кінці, можна використовувати лише для пошуку кінцяvector. Ви не можете його видалити. Далі, як тільки ви стерте ітератор, він пропаде. Ви не можете його безпечно використовувати після цього ні для чого, в тому числіd - i.