Категории выражений
Итак, открываем серию постов, посвященную внутренним сущностям компилятора C++. Их понимания будет достаточно, чтобы существенно повысить производительность ваших программ.
Наверняка в начале изучения языка вам приходилось сталкиваться с фундаментальными понятиями, такими как присвоение значения чему-либо:
Исходя из этого простого примера можно сделать вывод, что нельзя просто так взять и присвоить
Такая классификация действительно возможна и она называется категориями выражений. Итак, встречайте:
lvalue
Так называются те выражения, которыМ задают значение. Они должны быть модифицируемые. Зачастую они располагаются слева от знака равенства, поэтому и получили такое название left-hand value.
Представители этой категории расположены на стеке или куче, к которым разработчик может получить доступ и изменять их в пределах зоны видимости.
rvalue
К этой категории относятся выражения, которыЕ задают значения. Обычно они расположены справа от знака равенства - отсюда название right-hand value.
С представителями этой категории необходимо работать независимо от возможности доступа к стеку или куче; иметь возможность читать эти значения, без права изменять их как-либо.
prvalue
К этой категории относятся выражения, которые только задают значения. К такой категории относятся
Они являются подмножеством
xvalue
К этой категории относятся временные выражения, которые будут в скором времени уничтожены (eXpiring value). В некоторых случаях, их ресурсы могут быть эффективно переиспользованы. Пока оставлю вас без примера 😉
Думаю, не будет ошибкой заявить, что отношение к какой-либо категории определяет набор операций, которые могут быть выполнены над данными. С помощью этой модели компилятор проверяет, не совершил ли пользователь логическую ошибку и может принимать решения об оптимизации (исходя из ограничений).
При разборе этой темы так же рекомендую размышлять не только в рамках описанной модели, но и обращаться к своему опыту и знаниям, чтобы иметь некоторые ожидания от этой модели.
Мне так же следует сделать акцент на том, что категория выражений определяется окружающим кодом. Это означает, что в контексте текущей строчки кода категория выражений выводится исходя из предшествующего кода и операций, которые разработчик приказал выполнить. На следующей строчке эта категория может быть преобразована из исходной в другую.
Так, например, мы знаем, что нет никаких ограничений, чтобы скопировать переменную
Действительно,
Рассмотрим другой пример:
Хоть сумма
Продолжение в комментариях!
#cppcore #memory #algorithm
Итак, открываем серию постов, посвященную внутренним сущностям компилятора 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