Все временные значения r на С++?
Я занимаюсь кодированием на С++ в течение последних нескольких лет. Но есть один вопрос, который мне не удалось выяснить. Я хочу спросить, все ли временные в С++, rvalues?
Если нет, может ли кто-нибудь предоставить мне пример, где временный код в коде lvalue?
Ответы
Ответ 1
Нет.
Спецификация языка С++ никогда не делает такого простого утверждения, как тот, о котором вы просите. Он не говорит нигде в стандарте языка, что "все временные объекты являются rvalues". Более того, сам вопрос является немного неправильным, поскольку свойство быть rvalue на языке С++ не является свойством объекта, а скорее свойством выражения (т.е. Свойства его результата). Это на самом деле то, как оно определено в спецификации языка: для разных выражений он говорит, когда результат является значением lvalue и когда он является rvalue. Помимо всего прочего, это фактически означает, что к временному объекту можно получить доступ как значение r, так и lvalue, в зависимости от конкретной формы выражения, которая используется для выполнения доступа.
Например, результат выражения literal 2 + 3
, очевидно, является rvalue, временным типом int
. Мы не можем применить унарный &
к нему, поскольку унарный &
требует lvalue в качестве своего операнда
&(2 + 3); // ERROR, lvalue required
Однако, как мы все знаем, постоянная ссылка может быть привязана к временному объекту, как в
const int &ri = 2 + 3;
В этом случае ссылка привязана к временному, продлевая время жизни последнего. Очевидно, что как только это будет сделано, мы получим доступ к тому же временному, что и lvalue ri
, так как ссылки всегда lvalues. Например, мы можем легко и юридически применить унарный &
к ссылке и получить указатель на временный
const int *pi = &ri;
если этот указатель остается в силе до тех пор, пока сохраняется время.
Еще один очевидный пример доступа lvalue к временному объекту - это когда мы обращаемся к временному объекту типа класса с помощью его указателя this
. Результатом *this
является lvalue (как всегда бывает с результатом унарного *
, применяемого к указателю данных), но это не меняет того факта, что фактический объект может быть легко временным. Для данного типа класса T
выражение T()
является rvalue, как явно указано в стандарте языка, но временный объект, доступ к которому через выражение *T().get_this()
(с очевидной реализацией T::get_this()
), является lvalue. В отличие от предыдущего примера, этот метод позволяет сразу получить не-const-квалифицированное значение lvalue, которое относится к временному объекту.
Итак, опять же, тот же самый временный объект может быть легко "замечен" как rvalue или как lvalue в зависимости от того, какое выражение (какой путь доступа) вы используете для "поиска" на этом объекте.
Ответ 2
Prasoon Saurav уже связал очень хорошую тему clС++. Там Джеймс Канзе объясняет, почему вопрос не имеет смысла. Это сводится к:
- rvalue-ness - (логическое) свойство выражений - каждое выражение является либо lvalue, либо rvalue
- временные выражения не являются выражениями
По этой причине вопрос не имеет смысла.
Хорошим примером является следующий код:
int main() {
const int& ri = 4;
std::cout << ri << std::endl;
}
Временной int со значением 4
не является выражением. Выражение ri
, которое напечатано, не является временным. Это lvalue, и относится к временному.
Ответ 3
Хорошо, что оператор массива возвращает ссылку, любая функция, возвращающая ссылку, может считаться одной и той же? все ссылки являются константами, в то время как они могут быть lvalues, они изменяют то, что они ссылаются, а не сами ссылки. то же верно для оператора *
,
*(a temp pointer) = val;
Я клянусь, что использовал какой-то компилятор, который передавал временные значения любой функции, которая принимала ссылку,
чтобы вы могли пойти:
int Afunc()
{
return 5;
}
int anotherFunc(int & b)
{
b = 34;
}
anotherFunc(Afunc());
не может найти тот, который позволяет вам это сделать, однако ссылка должна быть const, чтобы разрешить передачу значений temp.
int anotherFunc(const int & b);
в любом случае, ссылки могут быть lvalues и временными, трюк, являющийся ссылкой, которую он сам не модифицировал, только то, что он ссылается.
если вы считаете оператор ->
как оператор, тогда временные указатели могут быть lvalues, но применяется одно и то же условие, а не указатель temp, который будет изменен, но то, на что оно указывает.
Ответ 4
Операция индексирования массива является временным и lvalue, что-то вроде [10] = 1 является примером того, что вы ищете; lvalue является временным, рассчитанным указателем.
Ответ 5
Это зависит от того, что вы считаете временной переменной. Вы можете написать что-то вроде
#include <stdio.h>
int main()
{
char carray[10];
char *c=carray+1;
*(c+2+4) = 9;
printf("%d\n",carray[7]);
return 0;
}
Это работает в VisualStudios и GCC. Вы можете запустить код в codepad
Я рассматриваю (c + 2 + 4) значение r, хотя я хочу назначить ему. Когда я разыграю его, он станет lvalue. Так что да все временные значения - это значения. Но вы можете сделать rvalues (таким образом, временным) в lvalue, разыменовывая его
Ответ 6
Короткий ответ: да, но я не буду приводить этот стандарт, потому что доказательство этого вопроса потребует решения всех временных времен. По определению временное имеет срок службы одного оператора, поэтому назначение вещей одному из них в лучшем случае будет плохим.
Интересный ответ: Копирование elision может сделать (часто делает) временный объект, идентичный объекту lvalue. Например,
MyClass blah = MyClass( 3 ); // temporary likely to be optimized out
или
return MyClass( 3 ); // likely to directly initialize object in caller frame
Изменить: как вопрос о том, есть ли в этих случаях какой-либо временный объект, в §12.8/15 упоминается
операция копирования может быть опущена путем конструирования временного объекта непосредственно в цель пропущенной копии
который указывает, что существует временный объект, который может быть идентичен lvalue.
Ответ 7
Если нет, может ли кто-нибудь предоставить мне пример, где временный код в коде является lvalue?
Следующий код связывает постоянную ссылку на временный объект типа const float
, созданный компилятором:
int i;
const float &cfr = i;
Поведение "как будто":
int i;
const float __tmp_cfr = i; // introduced by the compiler
const float &cfr = __tmp_cfr;