Const cast c как использовать
Перейти к содержимому

Const cast c как использовать

  • автор:

Оператор const_cast

Удаляет атрибуты const volatile и __unaligned атрибуты из класса.

Синтаксис

const_cast (expression) 

Замечания

Указатель на любой тип объекта или указатель на член данных можно явно преобразовать в тип, идентичный, за исключением const volatile квалификаторов, и __unaligned квалификаторов. Для указателей и ссылок результат будет указывать на исходный объект. Для указателей на данные-члены результат будет указывать на тот же член, что и исходный указатель (uncast) на данные-член. В зависимости от типа объекта, на который осуществляется ссылка, операция записи с помощью результирующего указателя, ссылки или указателя на данные-член может привести к неопределенному поведению.

Оператор нельзя использовать const_cast для прямого переопределения состояния константы переменной константы.

Оператор const_cast преобразует значение указателя NULL в значение null указателя целевого типа.

Пример

// expre_const_cast_Operator.cpp // compile with: /EHsc #include using namespace std; class CCTest < public: void setNumber( int ); void printNumber() const; private: int number; >; void CCTest::setNumber( int num ) < number = num; >void CCTest::printNumber() const < cout ( this )->number--; cout int main()

В строке, содержащей const_cast тип данных this указателя const CCTest * . Оператор const_cast изменяет тип this данных указателя CCTest * на , что позволяет изменять элемент number . Приведение выполняется только для оставшейся части оператора, в котором оно указано.

Const_cast

Author24 — интернет-сервис помощи студентам

Ребят, объясните мне, глупой, почему мы можем изменять const_cast-ом неконстантные объекты и всё ок, а изменить константный объект — UB. Что там такого происходит?

Заранее всем спасибо

Добавлено через 2 минуты
И сразу ещё один вопрос — что будет, если у константного объекта, который имеет поле mutable, изменить это поле? Что сработает? Вроде ж нельзя менять константный объект, но поле ж mutable.

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

const_cast
День добрый. Пытаюсь вот разобраться как работает данный оператор. Имеется пример: #include.

Const_cast ub
в каком-то видео для новичков увидел классный код такого плана const int x = 42; .

const_cast(*this)
Пусть есть некий class Foo < . >; std::wostream& operator<< (std::wostream &out, Foo.

Const_cast и mutable
В чем их отличие и когда их необходимо использовать (если не нарушена архитектура программы)?

Const и оптимизации в C

Сегодня на /r/C_Programming задали вопрос о влиянии const в C на оптимизацию. Я много раз слышал варианты этого вопроса в течении последних двадцати лет. Лично я обвиняю во всём именование const .

Рассмотрим такую программу:

void foo(const int *); int bar(void) < int x = 0; int y = 0; for (int i = 0; i < 10; i++) < foo(&x); y += x; // this load not optimized out >return y; >

Функция foo принимает указатель на const, который обещает от имени автора foo что значение x не будет изменено. Может показаться, что компилятор может предположить, что x всегда равен нулю, а значит и y тоже.

Однако, если мы посмотрим на ассемблерный код, генерируемый несколькими разными компиляторами, то увидим, что x загружается при каждой итерации цикла. Вот что выдал gcc 4.9.2 с -O3, с моими комментариями:

bar: push rbp push rbx xor ebp, ebp ; y = 0 mov ebx, 0xa ; цикл по переменной i sub rsp, 0x18 ; allocate x mov dword [rsp+0xc], 0 ; x = 0 .L0: lea rdi, [rsp+0xc] ; вычисляем &x call foo add ebp, dword [rsp+0xc] ; y += x (не оптимизировано?) sub ebx, 1 jne .L0 add rsp, 0x18 ; deallocate x mov eax, ebp ; возвращаем y pop rbx pop rbp ret

clang 3.5 (с -fno-unroll-loops) выдал примерно то же самое, только ebp и ebx поменялись местами, и вычисление &x вынесено из цикла в r14 .

Неужели оба компилятора не способны воспользоваться этой полезной информацией? Разве если foo изменит x , это не будет undefined behavior? Как ни странно, ответ — «нет». В этой ситуации, это будет абсолютно верным определением foo .

void foo(const int *readonly_x) < int *x = (int *)readonly_x; // cast away const (*x)++; >

Важно помнить, что const — не значит константный. Возьмите себе на заметку, что это неправильное название. Это не инструмент для оптимизации. Он нужен чтобы информировать программиста — а не компилятор — как инструмент, помогающий поймать определенный класс ошибок во время компиляции. Мне нравится, когда его используют в API потому что он сообщает, как функция будет использовать свои аргументы, или как вызывающий должен обращаться с возвращенными указателями. Обычно он недостаточно строгий, чтобы изменить поведение компилятора.

Несмотря на то, что я сказал, иногда компилятор может воспользоваться const для оптимизации. В спецификация C99, в §6.7.3¶5, есть одно предложение об этом:

Если сделана попытка изменить объект объявленный с модификатором const через использование lvalue без модификатора const, поведение неопределенно.

Исходный x был без модификатора const, поэтому это правило не применилось. И нет никакого правила против приведения к не- const типу, чтобы изменить объект который сам по себе не const . Это значит, что вышеприведённое поведение foo это не undefined behavior для этого вызова. Обратите внимание, что неопределенность foo зависит от того, как она была вызвана.

Одним изменением в bar я могу сделать это правило применимым, позволяя оптимизатору поработать.

 const int x = 0;

Компилятор теперь может предположить, что изменение x в foo — это undefined behavior, и потому никогда не происходит. Как бы то ни было, в основном так оптимизатор C рассуждает о ваших программах. Компилятор может предположить, что x никогда не изменяется, позволяя ему оптимизировать и загрузку в каждой итерации, и y .

bar: push rbx mov ebx, 0xa ; переменная цикла i sub rsp, 0x10 ; allocate x mov dword [rsp+0xc], 0 ; x = 0 .L0: lea rdi, [rsp+0xc] ; вычисляем &x call foo sub ebx, 1 jne .L0 add rsp, 0x10 ; deallocate x xor eax, eax ; возвращаем 0 pop rbx ret

Загрузка исчезает, y исчезает, и функция всегда возвращает ноль.

Любопытно, что спецификация позволяет компилятору пойти еще дальше. Он может разместить x где-нибудь вне стека, даже в read-only памяти. Например, он может произвести такую трансформацию:

static int __x = 0; int bar(void)

Или на x86-64 (-fPIC, модель малой памяти), где получается избавиться от еще нескольких инструкций:

section .rodata x: dd 0 section .text bar: push rbx mov ebx, 0xa ; переменная цикла i .L0: lea rdi, [rel x] ; вычисляем &x call foo sub ebx, 1 jne .L0 xor eax, eax ; возвращаем 0 pop rbx ret

Ни clang, ни gcc не заходят так далеко, видимо потому, что это более опасно для плохо написанного кода.

Даже со специальным правилом о const rule, используйте const для себя и своих товарищей-программистов. Пусть оптимизатор сам для себя решает, что константно, а что нет.

объясните по const_cast

Скажите вот читаю про const_cast. написано const_cast позволяет лишить статуса const или volatile переменную . Но такое ощущение , что не совсем ведь так буквально: потому что рассматривать её как полноценную переменную я не могу :

 const int i = 0; const_cast(&i); i = 555; 

но могу вот так :

 const int i = 0; int* j = const_cast(&i); *j = 555; 

то есть , если объявлено const int i = 0;, то после const_cast i можно менять только при помощи указателя ?

Отслеживать
задан 27 сен 2020 в 13:21
Андрей Гуренков Андрей Гуренков
425 3 3 серебряных знака 10 10 бронзовых знаков

Оно изменяет тип выражения, но не изменяет тип исходного объекта. Тип объекта в С/С++ всегда неизменяемый. Соответственно операции, которые можно проводить с результатом любого каста должны учитывать настоящий тип объекта. Попытка модифицировать объект с const квалификатором, как в *j = 555; , является неопределенным поведением.

27 сен 2020 в 13:39
Модификация во втором примере приводит к UB en.cppreference.com/w/cpp/language/const_cast
27 сен 2020 в 13:39

так если «попытка модифицировать объект с const квалификатором, как в *j = 555;, » это неопределенное повдение как пишет user7860670 , то какой смысл от const_cast, если первый мой пример бракует компилятор, а второй это UB ? честно говоря я не могу понять зачем надо константу делать переменной, ну да ладно. как тогда адекватно менять значение у константы после применения const_cast ?

27 сен 2020 в 13:54

@АндрейГуренков смысл const_cast : если возникла необходимость в нём, то понять, что проблема в дизайне/API, и, при возможности, поменять их; либо, если нельзя поменять, использовать const_cast , удостоверившись, что не будет модификации, и рассказав об этом в комментарии

27 сен 2020 в 14:08

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

const_cast саму переменную не меняет. Он просто возвращает указатель, который вы ему передали, с измененным типом: вы передали ему const int * , а на выходе получили int * , указывающий на ту же переменную.

Конечно, если не использовать то, что этот каст возвращает, тогда он вообще ничего не делает.

Ваш второй пример, хотя и компилируется, тоже некорректен (вызывает неопределенное поведение), потому что вы модифицируете константную переменную.

const_cast можно использовать только чтобы модифицировать неконстантную переменную, если у вас почему-то есть только указатель-на-const (или константная ссылка) на нее.

void f(const int *ptr) < // *ptr = 42; // Ошибка, потому что в указателе `const`. *const_cast(ptr) = 42; // Ок. > int main() < int foo = 0; // Ок. // const int foo = 0; // Не ок, неопределенное поведение из-за изменения константы. f(&foo); >

Отслеживать
ответ дан 27 сен 2020 в 13:47
HolyBlackCat HolyBlackCat
27.1k 3 3 золотых знака 27 27 серебряных знаков 40 40 бронзовых знаков

Вот учебная задача, выходит условие её не корректно : создайте const-массив double и volatile массив double. Переберите все элементы каждого массива в цикле, при помощи оператора const_cast отмените для каждого элементы const и volatile и присвойте ему значение.

27 сен 2020 в 14:01

@АндрейГуренков Да, оно действительно некорректно, если только вам не пытаются продемонстрировать, что это UB. Поругайте преподавателя за меня. 🙂

27 сен 2020 в 14:03
надо найти Брюса Эккеля и поругать . потому что задача от туда . книга 2004 года)))
27 сен 2020 в 14:04
@АндрейГуренков Значит ошибка в книге (если рядом нигде не написано, что будет UB, опять же).
27 сен 2020 в 14:08
понятие UB вообще не вводилось.
27 сен 2020 в 14:11

Присваивать объекту, который был определён как const — это в любом случае UB (undefined behavior). const_cast ни коим образом не снимает константность с самого объекта, он только «возвращает» переданное ему значение с нужным типом (это выражение также может быть «присваиваемым» (l-value)).

На практике const_cast используется довольно редко. Обычно это относительно грязный хак, чтобы передать константный объект в функцию, которая заведомо его не меняет (но принимает неконстантную ссылку/указатель) или, наоборот, изменить объект заведомо созданные как неконстантный, но переданный по константной ссылке/указателю. В тривиальном варианте это выглядит как-то так:

void foo (const int &i) < const_cast(i) = 2; > void bar (int *i) < std::cout // . int i=0; const int ci=2; foo(i); bar(const_cast(&ci)); 

По непосредственному вопросу: с точки зрения синтаксиса можно привести константную переменную к неконстантной ссылке (само собой так делать не стоит):

const int i = 0; const_cast(i) = 2; // !! UB !! 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *