Все ли временные значения в C ++? - PullRequest
33 голосов
/ 27 января 2010

Я программирую на C ++ в течение последних нескольких лет. Но есть один вопрос, который мне не удалось выяснить. Я хочу спросить, все ли временные значения в C ++, rvalues?

Если нет, может ли кто-нибудь предоставить мне пример, в котором временным произведением в коде является lvalue ?

Ответы [ 7 ]

43 голосов
/ 27 января 2010

номер

Спецификация языка C ++ никогда не дает такого простого утверждения, как то, о котором вы спрашиваете. В стандарте языка нигде не сказано, что «все временные объекты являются значениями». Более того, сам вопрос немного ошибочен, поскольку свойство быть значением в языке C ++ является не свойством объекта, а скорее свойством выражения (то есть свойством его результата). Это на самом деле так, как это определено в спецификации языка: для различных видов выражений говорится, когда результатом является lvalue, а когда это rvalue. Помимо прочего, это фактически означает, что временный объект может быть доступен как в виде значения, так и значения в зависимости от конкретной формы выражения, используемой для доступа.

Например, результатом литерального выражения 2 + 3, очевидно, является значение rvalue, временное значение типа int. Мы не можем применить к нему унарный &, так как унарный & требует lvalue в качестве операнда

&(2 + 3); // ERROR, lvalue required

Однако, как мы все знаем, постоянная ссылка может быть присоединена к временному объекту, как в

const int &ri = 2 + 3;

В этом случае ссылка прикрепляется к временному, продлевая срок службы последнего. Очевидно, что как только это будет сделано, мы получим доступ к тому же временному значению, что и lvalue ri, поскольку ссылки всегда являются lvalue. Например, мы можем легко и легально применить унарный & к ссылке и получить указатель на временный

const int *pi = &ri;

с указателем, который остается полностью действительным, пока сохраняется временное значение.

Другой очевидный пример доступа lvalue к временному объекту - это когда мы обращаемся к временному объекту типа класса через его указатель this. Результатом *this является lvalue (как всегда в случае с унарным *, примененным к указателю данных), но это не меняет того факта, что фактический объект может легко быть временным. Для данного типа класса T выражение T() является r-значением, как это явно указано в стандарте языка, однако временный объект, доступ к которому осуществляется через выражение *T().get_this() (с очевидной реализацией T::get_this()), является lvalue. В отличие от предыдущего примера, этот метод позволяет сразу получить неконстантное lvalue, которое ссылается на временный объект.

Итак, еще раз, тот же самый временный объект может легко «рассматриваться» как r-значение или как l-значение в зависимости от того, какое выражение (какой путь доступа ) вы используете, чтобы «посмотреть» «на этом объекте.

9 голосов
/ 27 января 2010

Prasoon Saurav уже связал очень хорошую ветку clc ++.Там Джеймс Канзе объясняет, почему вопрос на самом деле не имеет смысла.Это сводится к следующему:

  • rvalue-ness является (логическим) свойством выражений - каждое выражение является либо lvalue, либо rvalue
  • временные значения не выражения

По этой причине вопрос не имеет смысла.

Хорошим примером является следующий код:

int main() {
  const int& ri = 4;
  std::cout << ri << std::endl; 
}

Временный int со значением4 не является выражением.Выражение ri, которое напечатано, не является временным.Это lvalue, и относится к временному.

1 голос
/ 27 января 2010

хорошо, что оператор массива возвращает ссылку, можно ли считать, что любая функция, которая возвращает ссылку, делает то же самое? все ссылки являются константными, хотя они могут быть lvalues, они изменяют то, на что ссылаются, а не саму ссылку. то же самое верно для оператора *,

*(a temp pointer) = val;

Клянусь, я использовал какой-то компилятор, который передавал бы временные значения любой функции, которая взяла ссылку,

чтобы вы могли пойти:

int Afunc()
{
   return 5;
}

int anotherFunc(int & b)
{
    b = 34;
}


anotherFunc(Afunc());

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

int anotherFunc(const int & b);

в любом случае, ссылки могут быть lvalues ​​и временными, трюк, являющийся ссылкой, которую он сам не изменяет, только то, на что он ссылается.

если вы считаете оператор -> оператором, то временные указатели могут быть l-значениями, но применяется то же условие: не временной указатель, который будет изменен, а вещь, на которую он указывает.

0 голосов
/ 07 декабря 2011

Если нет, может ли кто-нибудь предоставить мне пример, в котором временное значение в коде является 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;
0 голосов
/ 27 января 2010

Краткий ответ: да, но я не собираюсь цитировать стандарт, потому что доказательство этого вопроса потребовало бы рассмотрения всех видов временных. По определению временный элемент имеет время жизни, равное одному выражению, поэтому присвоение элементов одному будет в лучшем случае плохим стилем.

Интересный ответ: Копия elision может сделать (часто делает) временный объект, идентичный объекту lvalue. Например,

MyClass blah = MyClass( 3 ); // temporary likely to be optimized out

или

return MyClass( 3 ); // likely to directly initialize object in caller's frame

Редактировать: Что касается вопроса о наличии какого-либо временного объекта в этих случаях, §12.8 / 15 упоминает

операция копирования может быть опущена путем создания временного объекта непосредственно в целевом объекте пропущенной копии

, который указывает на наличие временного объекта, который может быть идентичен lvalue.

0 голосов
/ 27 января 2010

Это зависит от того, что вы считаете временной переменной. Вы можете написать что-то вроде

#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. Вы можете запустить код в кодовой панели

Я считаю (c + 2 + 4) значением, хотя хочу присвоить ему. Когда я разыграю его, оно станет lvalue. Так что да, все временные являются ценностями. Но вы можете сделать rvalues ​​(таким образом, временным) lvalue, разыменовав его

0 голосов
/ 27 января 2010

Операция индексирования массива является как временной, так и lvalue, что-то вроде [10] = 1 является примером того, что вы ищете; lvalue является временным вычисляемым указателем.

...