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, отбрасывая constNess объекта и его изменение - UB. Цитата из "Заметки" здесь:

Даже если const_cast может удалить константность или изменчивость из любого указателя или ссылки, использование получающегося в результате указателя или ссылки для записи в объект, который был объявлен как const, или для доступа к объекту, который был объявлен как volatile, вызывает неопределенное поведение.

Подводя итоги ответов, я думаю, это лучше всего объясняет:

Допустимо брать константную ссылку на неконстантную переменную, а затем отбрасывать константу. Поэтому компилятор в первом случае не может предполагать, что func1 не изменится a,

Не определено, что произойдет, если вы отбросите константу в переменную, объявленную const. Компилятор во втором случае может предположить, что func1 не будет отбрасывать константу. Если func1 отбрасывает константу, func2 получит "неправильное" значение, но это только одно из следствий неопределенного поведения.

Другие вопросы по тегам