#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)
).)