Каков результат присваивания std :: vector <T>:: begin ()? - PullRequest
8 голосов
/ 29 марта 2019

Я немного разбираюсь в lvalue и rvalues.Так что, как я знаю, мы не можем присвоить rvalue, но неконстантное lvalue нормально.

#include <iostream>
#include <vector>
int main(){

    std::vector<int> v{ 1, 2, 3, 4, 5 };
    v.begin() = v.end() - 2;
    std::cout << *v.begin() << std::endl; // 1
    for (auto const& e : v)
        std::cout << e << ", ";// 1, 2, 3, 4, 5,
    std::cout << std::endl;
}

Почему я могу присвоить begin(), но оно ничего не делает с элементами?

Ответы [ 3 ]

17 голосов
/ 29 марта 2019

v.begin() - итератор.Присвоение итератору не присваивает значение, на которое указывает итератор.Кроме того, поскольку v.begin() является prvalue, объект, которому вы назначаете, уничтожается в конце строки, не затрагивая v или любую из «постоянных» памяти, которой он владеет.

Еслиv.begin() - это необработанный указатель, компилятор выдаст ошибку при попытке присвоить значение.Однако тип std::vector<T>::iterator часто является типом класса, и кажется, что это имеет место в вашей реализации (с конкретным набором используемых вами флагов компилятора), поэтому присвоение v.begin() вызывает operator= этоготип класса.Но это не меняет того факта, что объект итератора является временным объектом, и присвоение ему больше не влияет.

Чтобы присвоить элементу, на который указывает v.begin(), необходимо разыменоватьэто: *v.begin() = *(v.end() - 2)

6 голосов
/ 29 марта 2019

Каков результат присваивания std :: vector :: begin ()?

Результатом выражения присваивания (результат отбрасывается в вашем примере) является присвоенныйзначение.В этом случае результат совпадает с v.end() - 2.

. Обратите внимание, что, поскольку begin() возвращает значение, это назначение только изменяет возвращенный временный объект.Назначение не изменяет вектор в любом случае.Учитывая, что временный объект отбрасывается, назначение на практике не имеет наблюдаемых эффектов.

Кроме того, это назначение может быть некорректным, если стандартная библиотека выбрала для реализации std::vector::iterator в качестве указателя.

Почему я могу присвоить begin()

Поскольку

  1. Итераторы могут быть назначены.
  2. Можно присвоить значения типа класса.
  3. Итератор относится к типу класса.

, но он ничего не делает с элементами?

Потому что назначение итератора не изменяет элемент, на который указывает итератор.Вместо этого присваивание изменяет, на какой объект указывает итератор.

Так что, как я знаю, мы не можем присвоить rvalue

В общем, это неправильно.В частности, это неверно для типов классов .


Если только оператор присваивания класса не имеет lvalue-ref-qualifier (и имеетнет перегрузки с квалификацией rvalue-ref), что нетрадиционно.

3 голосов
/ 29 марта 2019

Иногда код объясняет вещи лучше, чем слова.Ваш код эквивалентен этому:

std::vector<int> v{ 1, 2, 3, 4, 5 };

{
    auto temp = v.begin();
    temp = v.end() - 2;
}

std::cout << *v.begin() << std::endl; // 1
for (auto const& e : v)
    std::cout << e << ", ";// 1, 2, 3, 4, 5,
std::cout << std::endl;

Другими словами, v.begin() = v.end() - 2 не имеет видимого эффекта.Это просто временное задание.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...