нетривиальный пример rvalue и lvalue

#c #lvalue-to-rvalue

#c #lvalue-to-rvalue

Вопрос:

Я не уверен в некоторых нетривиальных примерах rvalue / lvalue.

являются std::vector<int>({1,2,3})[0] std::vector<int>() ли выражения и ниже lvalue или rvalue?

код фактически не используется, но меня немного удивляет, что код действителен. Похоже, что они оба являются значениями lvalue. или нет?

 #include <vector>

int main()
{
    std::vector<int>({1,2,3})[0] = 0;
    std::vector<int>() = {1,2,3}; 
    return 0;
}
  

еще один пример…

Приведенное std::vector<int>() ниже выражение является значением rvalue. верно? а как насчет выражения std::vector<int>({1,2,3})[0] ?
Как векторный объект from std::vector<int>() , так и значение int from ...[0] являются временными значениями. верно?

 auto v = std::vector<int>();
int i = std::vector<int>({1,2,3})[0];
  

Комментарии:

1. У Дэна Сакса есть хорошая статья по этому поводу: youtube.com/watch?v=mK0r21-djk8

Ответ №1:

std::vector<int>() является значением rvalue, потому что синтаксис type() всегда выдает значение rvalue . std::vector<int>() = {1,2,3}; разрешено, потому что присвоение rvalues типа class разрешено в целом, но может быть отключено для определенного класса путем определения operator= с помощью amp; квалификатора, что std::vector не выполняется.

std::vector<int>({1,2,3})[0] является значением lvalue, поскольку std::vector<...>::operator[] определено для возврата ссылки на значение lvalue. Можно определить его для возврата rvalue или lvalue в зависимости от того, вызывается ли вектор для rvalue или lvalue (см. Ссылку выше), но std::vector он этого не делает.

Как векторный объект из std::vector(), так и значение int из …[0] являются временными значениями. верно?

Ответ vector — да. The int — нет, по крайней мере, формально.

Является ли объект временным или нет, зависит исключительно от способа его создания, например type() . всегда будет давать вам временное значение.

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

Комментарии:

1. Можно std::vector ли изменить, чтобы запретить изменение в качестве rvalue? Или стандарт требует, чтобы у него было его текущее поведение, поэтому стандарт должен быть изменен, если это поведение должно быть изменено.

2. @Eljay Стандарт требует текущего поведения. Если бы вы писали пользовательский вектор, вы могли бы это сделать.

3. @HolyBlackCat отличное объяснение. И последующий вопрос. Значение while autoamp; i = std::vector<int>(); недопустимо, autoamp; i = std::vector<int>(1)[0]; допустимо для компиляции, поскольку ..[0] не является временным. верно? это неопределенное поведение? как насчет времени жизни int из ...[0] ?

4. @rnd_nr_gen Он будет компилироваться и сам по себе не является UB, но любой доступ к ссылке после этого вызовет UB, потому что он сразу же становится зависшим.

5. …потому что вектор, будучи временным, уничтожается в конце полного выражения (здесь это означает at the ; ), и он забирает с собой свои элементы. Кроме того, небольшая деталь, но элемент, не являющийся временным, напрямую не делает эту строку допустимой. Что делает его действительным, так это то, что ...[0] возвращает значение lvalue. (Разница имеет значение, потому что в некоторых случаях вы можете получить значение rvalue, ссылающееся на временное (например, если вы делаете std::move ), или значение lvalue, ссылающееся на временное (например, если у вас есть int amp;foo(int amp;amp;x){return x;} , а затем вызываете foo(42) ).)