[Редактировать: ОК, поэтому этот вопрос более тонкий, чем я думал вначале.]
Объявление указателя на const или reference-of-const никогда не помогает компилятору оптимизировать что-либо. (Хотя см. Обновление внизу этого ответа.)
Объявление const
указывает только то, как идентификатор будет использоваться в пределах scope его объявления; это не говорит о том, что базовый объект не может измениться.
Пример:
int foo(const int *p) {
int x = *p;
bar(x);
x = *p;
return x;
}
Компилятор не может предположить, что *p
не изменяется при вызове bar()
, потому что p
может быть (например, указателем на глобальный int, а bar()
может изменить его.
Если компилятор знает достаточно о вызывающей стороне foo()
и содержимом bar()
, что он может доказать, что bar()
не изменяет *p
, тогда он также может выполнить это доказательство без объявления const .
Но это правда в общем. Поскольку const
влияет только на область действия объявления, компилятор уже может видеть, как вы обрабатываете указатель или ссылку в этой области; он уже знает, что вы не изменяете базовый объект.
Короче говоря, все, что делает const
в этом контексте - это предотвращает вас от ошибок. Он не сообщает компилятору ничего, чего он еще не знает, и поэтому он не имеет отношения к оптимизации.
А как насчет функций, которые вызывают foo()
? Как:
int x = 37;
foo(&x);
printf("%d\n", x);
Может ли компилятор доказать, что это печатает 37, поскольку foo()
занимает const int *
?
Нет. Даже если foo()
принимает указатель на const, он может отбросить константу и изменить int. (Это , а не неопределенное поведение.) Здесь снова, компилятор не может делать какие-либо предположения вообще; и если он знает достаточно о foo()
, чтобы сделать такую оптимизацию, он будет знать, что даже без const
.
Единственный раз, когда const
может разрешить оптимизацию, это случаи, подобные этому:
const int x = 37;
foo(&x);
printf("%d\n", x);
Здесь модифицировать x
через любой механизм (например, взять указатель на него и отбросить const
) - это вызвать неопределенное поведение. Таким образом, компилятор может предположить, что вы этого не делаете, и он может распространять константу 37 в printf (). Такая оптимизация допустима для любого объекта, который вы объявляете const
. (На практике локальная переменная, на которую вы никогда не берете ссылку, не принесет пользы, потому что компилятор уже может видеть, изменяете ли вы ее в своей области действия.)
Чтобы ответить на ваш вопрос "примечание стороны", (a) указатель const является указателем; и (b) константный указатель может быть равен NULL. Вы правы, что внутреннее представление (то есть адрес), скорее всего, одинаково.
[обновление]
Как указывает Кристоф в комментариях, мой ответ неполон, поскольку в нем не упоминается restrict
.
Раздел 6.7.3.1 (4) стандарта C99 гласит:
Во время каждого выполнения B пусть L будет любым lvalue, у которого & L основано на P. Если L используется для
получить доступ к значению объекта X, который он обозначает, и X также изменяется (любым способом),
тогда применяются следующие требования: T не должен быть постоянным. ...
(Здесь B - базовый блок, над которым находится P, указатель ограничения на T).
Итак, если функция C foo()
объявлена так:
foo(const int * restrict p)
... тогда компилятор может предположить, что никаких изменений в *p
не произойдет в течение жизненного цикла p
- т.е. во время выполнения foo()
- потому что в противном случае Поведение будет быть неопределенным.
Таким образом, в принципе, объединение restrict
с указателем на const может включить обе оптимизации, которые были отклонены выше. Интересно, какие-нибудь компиляторы реализуют такую оптимизацию? (GCC 4.5.2, по крайней мере, нет.)
Обратите внимание, что restrict
существует только в C, но не в C ++ (даже не в C ++ 0x), за исключением расширения для конкретного компилятора.