Неопределенное поведение при преобразовании const_cast

by Sergey Afonin

Несмотря на то, что C++ предоставляет возможность принудительного изменения типа переменной или "снятия" модификатора const, использование в программах этих методов не рекомендуется и считается плохим тоном. Расмотрим в качестве иллюстрации функцию, которая получает ссылку на константное целое, но изменяет его значение.

void set_value(const int &var, int value) {
    int &non_const_var = const_cast<int &>(var);
    non_const_var = value;
} 
В данном примере ссылка на константный объект var преобразуется к ссылке на изменяемый объект. Поскольку переменная non_const_var имеет тип int &, то она ссылается на существующий объект типа int. Изменение значения non_const_var изменяет и объект var, так как var и non_const_var являются двумя названиями одного объекта в памяти. В теории.

Поведение данной функции зависит от того, каким образом она была вызвана. В приведенном ниже прмере будет выведено вполне ожидаемое сообщение "k = 1".

#include <iostream>

int main() {
    int k = 0;
    set_value(k, 1);
    std::cout << "k = " << k << std::endl; // k = 1
} 
Если же переменная k будет объявлена константной, то поведение программы неопределено.
#include <iostream>

int main() {
    const int k = 0;
    set_value(k, 1);
    std::cout << "k = " << k << std::endl; // k = 0 !!!
} 
Вероятнее всего, значение переменной k не изменится.

Разница между этими примерами состоит в том, что в последнем случае компилятор может, поскольку переменная k объявлена неизменяемой, либо разместить ее в недоступной для изменения области памяти, либо вообще заменить все вхождения k константой 0. В любом случае модификация значения k будет некорректной. Заметим, что функция set_value не может различить эти ситуации, а потому является небезопасной.

Thanks for reading.