TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.36K subscribers
Post #114 1.71K
​Категории выражений

Итак, открываем серию постов, посвященную внутренним сущностям компилятора C++. Их понимания будет достаточно, чтобы существенно повысить производительность ваших программ.

Наверняка в начале изучения языка вам приходилось сталкиваться с фундаментальными понятиями, такими как присвоение значения чему-либо:
  
int a, b;

a = 3; // Корректно
b = a; // Корректно
3 = b; // Ошибка


Исходя из этого простого примера можно сделать вывод, что нельзя просто так взять и присвоить 3 какое-то новое значение. Хотя, казалось бы, это должно быть очень веселым занятием 😊 Напрашивается вопрос, можно ли как-то классифицировать выражения по действиям над ними? Существуют ли еще какие-то особые правила?

Такая классификация действительно возможна и она называется категориями выражений. Итак, встречайте:

lvalue
Так называются те выражения, которыМ задают значение. Они должны быть модифицируемые. Зачастую они располагаются слева от знака равенства, поэтому и получили такое название left-hand value.
  
lvalue
a = 3;


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

rvalue
К этой категории относятся выражения, которыЕ задают значения. Обычно они расположены справа от знака равенства - отсюда название right-hand value.
        rvalue
a = b;


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

prvalue
К этой категории относятся выражения, которые только задают значения. К такой категории относятся constexpr, литералы и т.д. Например:
        prvalue
a = 3;


Они являются подмножеством rvalue, и в дальнейшем мы не будем делать на этом акцент.

xvalue
К этой категории относятся временные выражения, которые будут в скором времени уничтожены (eXpiring value). В некоторых случаях, их ресурсы могут быть эффективно переиспользованы. Пока оставлю вас без примера 😉


Думаю, не будет ошибкой заявить, что отношение к какой-либо категории определяет набор операций, которые могут быть выполнены над данными. С помощью этой модели компилятор проверяет, не совершил ли пользователь логическую ошибку и может принимать решения об оптимизации (исходя из ограничений).

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

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

Так, например, мы знаем, что нет никаких ограничений, чтобы скопировать переменную a в b. Значит, переменная a может быть преобразована к rvalue :
  
lvalue rvalue
a = 3;

lvalue lvalue -> rvalue
b = a;


Действительно, lvalue может быть неявно приведено к rvalue, но не наоборот! Так, например, численная константа 3 независимо от контекста всегда будет rvalue, т.к. её значение нельзя поменять ни при каких обстоятельствах. Если это правило нарушается, компилятор вполне заслуженно бьет по рукам.

Рассмотрим другой пример:
rvalue     rvalue 
(a + b) = a // Ошибка!


Хоть сумма a + b и может быть образована из двух lvalue, но оператор + возвращает rvalue. Результат сложения должен быть присвоен другой переменной или использован для других операций. По сути, он не был сохранен в переменную на стек или кучу из области видимости, поэтому как ему можно присвоить хоть какое-то иное значение?

Продолжение в комментариях!

#cppcore #memory #algorithm
  • 🔥 22
  • 👍 13
  • ❤ 10
  • ⚡ 1
  • 🆒 1
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →