пятница, 22 июня 2012 г.

Категории значений С++

Все выражения делятся на следующие категории значений:
            Каждое выражение принадлежит ровно одной категории значений: lvalue, xvalue или prvalue. В процессе вычисления, выражение может переходить из одной категории значений в другую, но все выражения, в конечном итоге, преобразовываются к категории значений rvalue.
            Например: выражение может сначала быть lvalue, после чего преобразуется к rvalue.

            В общем, все категории значений можно разделить на два видалевосторонние (изменяемые) и правосторонние (не изменяемые).

операнд_1 = операнд_2;

Где:
Операнд-1 – левостороннее значение (glvalue, lvalue, xvalue – ссылка на правосторонние данные).  
Операнд-2 – левостороннее значение или правостороннее значение (rvalue, prvalue, xvalue – результат выражения с prvalue или ссылками на rvalue).


Общий пример.

int f0() { int i = 23; return i; }
int& f1() { int i = 23; return i; }

int main()
{
   int p = 5;
   //&5;                         // Ошибка. Выражение должно быть lvalue.
   &p;                           // Ок.
   int *t = &p;                  // Ок.
   &t;                           // Ок.
   //&(double)p;         // Ошибка. Выражение должно быть lvalue.
   &(double&)p;                  // Ок.
   double *x = &*(double*)&p;    // Ок.
   cout << *(int*)x << endl;
   //&f0();                      // Ошибка. Выражение должно быть lvalue.
   cout << &f1() << endl;        // Ок.
   return 0;
}
lvalue
1.     lvalue назван так исторически, так как он ​​может находиться с левой стороны в операциях присвоения.  lvalue (левосторонние данные) – данные, которым можно присвоить какое-либо значение и адрес расположения этих данных в памяти можно получить используя оператор «&». 

К левосторонним данным относятся.
1.     Переменные:                   int b = 5; int temp; temp = b;

2.     Ссылка (в момент явного приведения с созданием временной ссылки ((тип&)lvalue)):                                int a = 5; (double&)a = 23.23;

3.     Раскрытый указатель / адрес:      int *p = new int(23);    *p = 5;
int a = 5; *(double*)&a = 23.23; // Извлекаем адрес, по которому расположена переменная-а, приводим этот адрес к типу double*, раскрываем этот адрес, после чего по этому же адресу неявно создается временная переменная типа double, которой присваивается константна. 

4.     Нераскрытый указатель, если ему присваивается адрес:
int main() 
{
   int a = 23;  int *p = new int(); int *q = new int();
   p = q;                        // Присваиваем адрес, присвоенный указателю q.
   p = &a;                       // Присваиваем адрес переменной.
   p = new int(5);               // Присваиваем адрес выделенной памяти.
   return 0;
}

5.     Возвращаемое значение функции по ссылке, указателю; в этом случае, на месте инициатора вызова функции, будет подставлено левостороннее значение.
int& f1(int& a)          { return a;  }                    // Возвращает ссылочную переменную.
int* f2(int& a)          { return &a; }                    // Возвращает адрес, на который ссылается ссылка.
int*& f3(int*& a)        { return a;  }                    // Возвращает ссылочную переменную-указатель.

int main()
{
   int a = 5, b = 10, temp;
   int *p = new int(23);
   cout << "a == " << a << " " << ", b == " << b << ", *p == " << *p << endl;
   temp  = a;              
   f1(a) = b;                     // f1(a) - левостороннее значение.
   *(f2(b)) = temp;               // f2(b) - правостороннее значение. *(f2(b)) - левостороннее значение.
   p = &temp;                     // Имя указателя - левостороннее значение.
   f3(p) = &temp;                 // f3(p) - левостороннее значение.
   cout << "a == " << a << " " << ", b == " << b << ", *p == " << *p << endl;  
   return 0;
}

rvalue
1.     r-value назван так исторически, так как он ​​может находиться с правой стороны в операциях присвоения. 
2.     r-value (правосторонние данные) – это данные, которые можно присвоить левосторонним данным и адрес расположения этих данных в памяти нельзя получить используя оператор «&».
3.     Результатом всех выражений всегда есть rvalue



К правосторонним данным относятся.

1.     Результат применение оператора &.
int a = 23;
&a;              // Результат взятия адреса - правостороннее значение.
//&a = 5;        // Недопустимо: попытка выполнить присвоение правосторонним данным.

2.     Приведение значения дает r-value.
int main()
{
 int i = 5;
 //(double)i = 23.23; // Ошибка. (double)i - приведение значения дает r-value.
 return 0;
}

Исключение (VS2012): приведение значения к своему же типу дает l-value.
 
int main()
{
   int x = 23;
   const int &s = x;
   (int)s = 32;
   //(unsigned)s = 32; // Ошибка. Результатом приведения к другому типу является r-value.
   cout << x << endl;
   return 0;
}

3.     Результат вызова функции, тип возвращаемого значения которой не является ссылка.

int r()                                   // Возвращает rvalue
{ return 0; }


int f() { int i = 23; return i; }

int main()
{
    int a = f();     // Ок. f() возвращает правостороннее значение, может быть присвоено другим данным.
    f();             // Эквивалентно: 23; - чистое правостороннее значение.
    //f() = 5;       // Недопустимо: попытка выполнить присвоение чистым правосторонним данным.       
    return 0;
}
xvalue
xvalue («eXpiring» - «разрушающееся» значение) ссылается на объект, как правило, ближе к концу его жизни. xvalue относится к категории glvalue только в том случае, если glvalue преобразуется в выражении к xvalue, во всех остальных случаях xvalue относиться к категории rvalue.


1. xvalue является результатом определенных видов выражений, содержащих rvalue ссылки.

int&& i = 5 + 5;         //5 + 5 создает xvalue == 10
i;                       //iglvalue, т.к. к нему можно применить оператор &.

2. Результат преобразования rvalue к ссылке на правосторонние данные есть xvalue, полученное из категории rvalue.

(int&&)23.23;  // rvalue преобразуется к xvalue.


3. Результат вызова функции, тип возвращаемого значения которой является ссылка на rvalue, считается xvalue.

int&& x()                                 // Возвращает xvalue
{
        return 0;
        return 0 + 0;
}
glvalue
glvalue («generalized» - «обобщенное» lvalue) является lvalue или xvalue. К glvalue можно применить оператор «&».


1. Результат преобразования glvalue к ссылке на правосторонние данные есть xvalue, полученное из категории glvalue.

int i = 0;
(int&&)i;      // glvalue преобразуется к xvalue.


2. Создание ссылки на правосторонние данные:

int&& i = 5;             // 5 – prvalue.
i;                       // iglvalue, т.к. к нему можно применить оператор &.

prvalue
prvalue («pure» «чистая» rvalue) – значение констант.
1.   Константы:                 
23;
7.3E
true   

3 комментария:

  1. Не могли бы Вы хотя бы кратко своими словами пояснить, что такое xvalue? И какое практическое значение у такой сущности?

    ОтветитьУдалить
  2. xvalue («eXpiring» - «разрушающееся» значение). Это любая временная, неименованная сущность, которая участвует в некотором выражении и разрушается после выполнения данного. Может относиться к glvalue или к rvalue, в зависимости от того, может ли такая сущность находиться слева в операторе присвоения.

    Пример 1:

    int* p = new int;
    *p = 5; // тут на месте *p создается xvalue, которому можно что-то присвоить, значит эта xvalue еще и glvalue.

    Пример 2:

    int foo(); // ф-я возвращает временную сущность, которая тоже разрушится, но ей ничего нельзя присвоить, значит эта xvalue относится к rvalue.

    ОтветитьУдалить
  3. ВСЕ ПРОЧИТАЙТЕ НАСТОЯЩЕЕ ОТЗЫВ О том, КАК Я ПОЛУЧИЛ СВОЙ КРЕДИТ ОТ КОМПАНИИ LEGIT И ДОВЕРЕННОЙ КРЕДИТНОЙ СРЕДИ Меня зовут Kjerstin Lis, я искал кредит для погашения своих долгов, все, кого я встречал, мошенничали и брали свои деньги, пока я наконец не встретил мистера Бенджамина Брейл Ли Он смог дать мне кредит в размере 450 000 рублей. Он также помог другим моим коллегам. Я говорю как самый счастливый человек во всем мире сегодня, и я сказал себе, что любой кредитор, который спасает мою семью от нашей бедной ситуации, я скажу имя всему миру, и я так счастлив сказать, что моя семья вернулся навсегда, потому что я нуждался в кредите, чтобы начать свою жизнь заново, потому что я одинокая мама с 3 детьми, и весь мир, казалось, висел на мне, пока я не имел в виду, что БОГ послал кредитора, который изменил мою жизнь и член моей семьи, БОЖИЙ кредитор, мистер Бенджамин, он был Спасителем БОГом, посланным для спасения моей семьи, и сначала я подумал, что это будет невозможно, пока я не получу кредит, я пригласил его к себе в семью -все вечеринка, от которой он не отказался, и я посоветую всем, кто действительно нуждается в кредите, связаться с г-ном Бенджамином Брейлом Ли по электронной почте (lfdsloans@outlook.com), потому что он самый понимающий и добрый кредитор. когда-либо встречал с заботливым сердцем. Он не знает, что я делаю это, распространяя свою добрую волю ко мне, но я чувствую, что должен поделиться этим со всеми вами, чтобы освободить себя от мошенников, пожалуйста, остерегайтесь подделок и свяжитесь с правильной кредитной компанией. com или whatsapp + 1-989-394-3740. ,

    ОтветитьУдалить