Пожалуйста, рассмотрите следующий код:
void func1(const int &i);
void func2(int i);
void f()
{
int a=12;
func1(a);
func2(a);
}
Скомпилированный с g ++ 4.6 с -O3, я вижу, что скомпилированный перечитывает значение «a» между вызовами функции. Изменив определение a на «const int», компилятор этого не делает, а просто загружает непосредственное значение «12» в edi. То же самое верно, если a не является константой, но я изменяю сигнатуру func1 для принятия по значению.
Хотя это и не ошибка в генерации кода, это все же странное поведение. Так как func1 взял на себя обязательство не менять a, почему код компилятора должен меняться в зависимости от того, является ли a константным или нет?
редактироватьНекоторые скептики утверждают, что я могу неправильно читать код. Приведенный выше код создает следующее с компиляцией -S:
_Z1fv:
.LFB0:
.cfi_startproc
subq $24, %rsp
.cfi_def_cfa_offset 32
leaq 12(%rsp), %rdi
movl $12, 12(%rsp)
call _Z5func1RKi
movl 12(%rsp), %edi <-- Rereading a
call _Z5func2i
addq $24, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
Изменение на const приводит к:
_Z1fv:
.LFB0:
.cfi_startproc
subq $24, %rsp
.cfi_def_cfa_offset 32
leaq 12(%rsp), %rdi
movl $12, 12(%rsp)
call _Z5func1RKi
movl $12, %edi <-- Use immediate value
call _Z5func2i
addq $24, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
В C ++ const
на самом деле просто логическое постоянство, а не физическое постоянство. func1
может сделать const_cast
и изменить i
, const
это как безопасность пистолета — вы все равно можете выстрелить себе в ногу, но не случайно.
Как Т.С. и juanchopanza указали в комментариях, отбрасывая const
Ness объекта и его изменение — UB. Цитата из «Записок» Вот :
Даже если const_cast может удалить константу или изменчивость из любого указателя или ссылки, использование полученного указателя или ссылки для записи в объект, который был объявлен как const, или для доступа к объекту, который был объявлен как volatile, вызывает неопределенное поведение.
Подводя итоги ответов, я думаю, это лучше всего объясняет:
Допустимо использовать константную ссылку на неконстантную переменную, а затем отбрасывать константу. Поэтому компилятор в первом случае не может предполагать, что func1 не изменится a
,
Неизвестно, что произойдет, если вы отбросите constness в переменную, объявленную как const. Компилятор во втором случае может предположить, что func1 не будет отбрасывать константу. Если func1 отбрасывает константу, func2 получит «неправильное» значение, но это лишь одно из следствий неопределенного поведения.