2017-02-06 15 views
2

Скажем, у меня есть вектор v {1, 2, 3, 4, 5}. Я хотел бы, чтобы вырезать последние два элемента, так что я думал, что сделать что-то вродеC++, присваивая значение вектору :: end?

v.end() = v.begin() + 3; 

Давайте этот фрагмент:

std::vector<int> v {1,2,3,4,5}; 
std::cout << *(v.end()-1) << std::endl; 
v.end() = v.begin() + 3; 
std::cout << *(v.end()-1) << std::endl; 

Печатается 5 в обоих случаях. Почему это? Если vector :: end возвращает итератор, разве это не значение rvalue? Если это так, код не должен компилироваться вообще. Если это значение lvalue, почему конечный итератор не указывает на элемент v.begin() + 3?

+0

Если вы хотите узнать, можете ли вы назначить rvalue, вы должны использовать менее запутывающий пример. Если вы хотите знать, как «вырезать последние два элемента» из вектора, то, возможно, вы можете удалить материал rvalue. Эти два вопроса мешают друг другу и неясны. – juanchopanza

+0

Хорошо, я буду помнить это о будущем, спасибо – user6646922

+0

@juanchopanza: Это не совсем справедливое замечание. Вы должны предположить, что кто-то с вопросом не имеет полного понимания проблемы, это ведь почему они спрашивают. Если вы на уровне C++, который вы придумали вышеприведенный код, то небезосновательно ожидать, что вы знаете более тонкие точки относительно lvalues ​​и rvalues. Таким образом, вы можете увидеть, что это не сработало, и начать рассуждать о том, что происходит, и в конечном итоге поставить вопрос выше. И учитывая, что это реальный компилируемый код, с ожидаемыми и фактическими результатами, я бы сказал, что это правильно для StackOverflow. – MSalters

ответ

3

Каждый раз, когда вы вызываете v.end(), возвращается новый объект итератора. Это значение rvalue, но вы все равно можете изменить его значение, но это не влияет на контейнер, ваш v. Если вы хотите удалить что-либо из вектора, используйте, например, vector::erase().

+0

Я думаю, вы имеете в виду, что это rvalue. – juanchopanza

+0

Хм, нет? Это объект (тип итератор), он занимает память, вы можете присвоить ему что-то -> это значение lvalue. – Rene

+0

Это rvalue. 'v.end()' - выражение rvalue (вы можете легко это проверить, написав пару функций: void foo (const vector :: iterator &); 'и' void foo (vector :: iterator &&) 'и посмотреть какая одна перегрузка ресулирует.) – juanchopanza

2

Вы не можете назначить итератор конца так, как вам нужно удалить.

v.erase(v.begin() + 3, v.end()); 
9

std::end() возвращает итератор, который указывает на элемент после последнего одного. Его можно использовать только как ссылку (например, сравнить другой итератор с ним), попытка использовать его значение - неопределенное поведение.

Это, как говорится, этот код v.end() = v.begin() + 3; просто переставляет копию итератора, который вы получили от вектора, он не модифицирует сам вектор.

Рассмотрите возможность использования одной из перегрузок erase, чтобы нарезать часть вектора.