Оптимизатор: замените константу const на объект const
Чандлер Каррут в своем беседе о оптимизации компилятора сказал, что компиляторы ужасны при оптимизации функций с параметрами, переданными по ссылке. Я могу понять, что трудно, когда параметр является неконстантной ссылкой, поскольку компилятор должен иметь дело с памятью или когда тип параметра является сложным (какая-то странная структура или класс). Но если параметр является ссылкой на const и встроенным типом, есть ли какие-либо проблемы? Может ли оптимизатор заменить const float&
на const float
? Это может быть еще более полезно, когда использование инструкций SSE включено, поскольку компилятор сможет правильно выровнять данные для них.
Ответы
Ответ 1
Может ли оптимизатор заменить const float&
на const float
?
Нет, они не могут этого сделать, потому что это может изменить семантику программы. Ссылка const
по-прежнему является ссылкой. Он не может быть заменен значением. Рассмотрим этот пример:
void foo(const float& x, float a[]) {
cout << x << endl;
a[0] += 10.5;
cout << x << endl;
}
int main() {
float a[1] = { 3.25 };
foo(a[0], a);
return 0;
}
Отпечатает
3.25
13.75
Демо 1
Если вы измените const float&
на const float
, результат будет
3.25
3.25
Демо 2
Проблема заключается в том, что a[0]
совпадает с x
, но соединение устанавливается вызывающим абонентом, который находится вне контроля оптимизатора.
Ответ 2
Я выслушал, что поговорил на Youtube некоторое время назад.
Оптимизатор не может заменить ссылки, если он не знает, что делает функция на самом деле. Например.
func.c:
float func(const float& f)
{
return f * 2;
}
main.c:
float complicated()
{
float f = 3.0;
float f2 = func(f);
f2 += 42 + f;
return f2 / 17.0;
}
int main()
{
std::cout << complicated() << std::endl;
}
Так что даже tho 'f
в сложном не изменяется в func
, компилятор не знает этого. Поэтому он должен передать f
в качестве ссылки, а func
.
Если функция является встроенной (потому что она в том же источнике и достаточно коротком), то она действительно может встроить эту функцию и удалить использование ссылки. Но если источник функции находится в другой функции, вы не можете знать, что делает эта функция.
Если источник недоступен, компилятор должен пройти по ссылке, потому что это контракт функции - аргументы передаются по-разному для одной вещи, но даже если это не так [поскольку dasblinkenlight показывает, что ответ] смысл кода может измениться, если аргумент является ссылкой или нет.
Ответ 3
Еще одна причина, почему эта подстановка не может быть сделана, состоит в том, что функция может фактически const отбросить константу, а затем мутировать переменную, которая будет отражена в области вызова. Это только UB, если переменная, переданная в const, является константой. То есть:
void f(const int & x) {
const_cast<int &>(x) = 0;
}
int x = 1;
f(x);
Является законным и делает то, что вы ожидаете. Конечно, этот код отвратительный и т.д., Но все же законный. Измените ссылку const на байпас по значению, и вы измените программу, сделав компилятор несоответствующим. Из-за const_cast и того, как широко он может быть использован, компиляторы действительно не используют const (за исключением, в некоторой степени, локальных переменных); Чандлер упоминает об этом также в одном из своих разговоров.
Ответ 4
Но если параметр является ссылкой на const и встроенным типом действительно ли какие-либо проблемы?
Это не для того, чтобы быть "сложным" или встроенным типом, который "трудно" оптимизировать. Проблема заключается в сглаживании, которое является гораздо худшим зверем для решения проблемы, которая затрагивает указатели и ссылки из-за их внутренней природы.
Может ли оптимизатор заменить const float & с const float?
@dasblinkenlight является очень хорошим примером того, что оптимизация невозможна, поскольку она влияет на видимое поведение кода, который оптимизаторы не могут изменить. Реальная регрессия состоит в том, что обычно sizeof (float&) > sizeof(float)
, поэтому вы технически потребляете больше байтов для этого параметра; в то время как true, это фактически не имеет значения, особенно если оно передано в регистр.
Для ограниченного доступа к памяти, как по счету, так и по побочным эффектам, сглаживание вряд ли будет проблемой или все же не стоит использовать методы, чтобы попытаться его оптимизировать.