C++ зависимость от аргумента константной ссылки не меняется
Пожалуйста, рассмотрите следующий код:
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
2 ответа
В C++ const
на самом деле просто логическое постоянство, а не физическое постоянство. func1
может сделать const_cast
и изменить i
, const
это как безопасность пистолета - вы все равно можете выстрелить себе в ногу, но не случайно.
Как указали в комментариях TC и juanchopanza, отбрасывая const
Ness объекта и его изменение - UB. Цитата из "Заметки" здесь:
Даже если const_cast может удалить константность или изменчивость из любого указателя или ссылки, использование получающегося в результате указателя или ссылки для записи в объект, который был объявлен как const, или для доступа к объекту, который был объявлен как volatile, вызывает неопределенное поведение.
Подводя итоги ответов, я думаю, это лучше всего объясняет:
Допустимо брать константную ссылку на неконстантную переменную, а затем отбрасывать константу. Поэтому компилятор в первом случае не может предполагать, что func1 не изменится a
,
Не определено, что произойдет, если вы отбросите константу в переменную, объявленную const. Компилятор во втором случае может предположить, что func1 не будет отбрасывать константу. Если func1 отбрасывает константу, func2 получит "неправильное" значение, но это только одно из следствий неопределенного поведения.