[Редагувати: Добре, тому це питання є більш тонким, ніж я думав спочатку.]
Оголошення покажчика на const або посилання на const ніколи не допомагає жодному компілятору щось оптимізувати. (Хоча див. Оновлення внизу цієї відповіді.)
const
Декларація вказує на те, як тільки ідентифікатор буде використовуватися в межах обсягу його декларації; це не говорить про те, що основний об'єкт не може змінитися.
Приклад:
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()
приймає a const int *
?
Ні. Незважаючи на те, що foo()
приймає покажчик на const, він може відкинути const-ness і змінити int. (Це не є невизначеною поведінкою.) І тут компілятор взагалі не може робити жодних припущень; і якщо він знає достатньо про те, foo()
щоб зробити таку оптимізацію, він буде знати, що навіть без const
.
Єдиний час, який const
може дозволити оптимізацію, - це такі випадки:
const int x = 37;
foo(&x);
printf("%d\n", x);
Тут модифікувати за x
допомогою будь-якого механізму (наприклад, взявши вказівник на нього та відкинувши його const
) означає викликати невизначену поведінку. Тож компілятор може вільно припустити, що ви цього не робите, і він може розповсюдити константу 37 у printf (). Така оптимізація є законною для будь-якого об’єкта, який ви заявляєте const
. (На практиці локальна змінна, на яку ви ніколи не посилаєтесь, не виграє, оскільки компілятор вже бачить, чи ви її змінюєте в межах своєї сфери дії.)
Щоб відповісти на ваше запитання "побічної ноти", (a) покажчик const - це покажчик; і (b) покажчик const може дорівнювати NULL. Ви праві, що внутрішнє подання (тобто адреса), швидше за все, однакове.
[оновлення]
Як зазначає Крістоф у коментарях, моя відповідь є неповною, оскільки в ній не згадується restrict
.
Розділ 6.7.3.1 (4) стандарту C99 говорить:
Під час кожного виконання B, нехай L - будь-яке значення l, яке має & 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), за винятком розширення, специфічного для компілятора.
const
, але в основному для людей, і коду, який ми пишемо; компілятор не може нічому довіряти, а тому він не може розумно виграти таким же чином.