2009-10-09 15 views
5

В C++ У меня есть функция, которая требует только доступ только для чтения к массиву, но ошибочно объявлен как получающий неконстантную указатель:Использует const_cast для доступа только для чтения к объекту const?

size_t countZeroes(int* array, size_t count) 
{ 
    size_t result = 0;   
    for(size_t i = 0; i < count; i++) { 
     if(array[i] == 0) { 
      ++result; 
     } 
    } 
    return result; 
} 

и мне нужно вызвать его константный массив:

static const int Array[] = { 10, 20, 0, 2}; 

countZeroes(const_cast<int*>(Array), sizeof(Array)/sizeof(Array[0])); 

будет ли это неопределенным поведением? Если это так - когда программа запустится в UB - при выполнении const_cast и вызове functon или при доступе к массиву?

+0

Я полагаю, вы не можете изменить объявление функции ... но я настоятельно рекомендую вам написать обертку с лучшей и сделать грязную работу внутри нее. –

+0

Возможно, попробуйте совсем другое: 'size_t numZeros = std :: count (Array, Array + sizeof (Array)/sizeof (Array [0]), 0);' – MP24

+0

@ MP24 Эта функция представляет собой просто иллюстрацию проблема. – sharptooth

ответ

13

Да, разрешено (если опасно!). Это фактическая запись в объект const, который несет неопределенное поведение, а не сам листинг (7.1.5.1/4 [dcl.type.cv]).

Как стандартные примечания в 5.2.11/7 [expr.const.cast], в зависимости от типа объекта попытка записи через указатель, являющийся результатом отбрасывания const, может приводить к неопределенному поведению.

-2

Использование const_cast на объекте, который изначально определен как const, является UB, поэтому неопределенное поведение происходит немедленно в точке, которую вы вызываете const_cast.

+3

№ UB находится в момент написания объекта const, а не удаления константы. –

+0

Ой, прости, жаль, что у меня возникли противоречивые советы по интерведам –

+3

Эти веб-сайты могут быть сложными. – GManNickG

1

Поскольку ваш код не изменяет массив, и вы сказали компилятору, что знаете, что вы делаете, используя const_cast, на самом деле все будет в порядке. Однако я считаю, что вы технически ссылаетесь на неопределенное поведение. Лучше всего, чтобы объявление функции фиксировалось или записывалось, объявляло и использовало его полную версию.

+0

попробуйте прочитать, как использовать константу в «Эффективном C++» или «Более эффективный C++». Он также показывает некоторые допустимые варианты использования const_cast (например, чтобы избежать дублирования кода). –

+0

-1 потому что это не неопределенное поведение; исторически это сделало бы код C++ 98 сложным для взаимодействия с пред-стандартным C. Однако я полностью согласен с вами в этом совете. –

1

Да, вы можете это сделать. Нет, это не неопределенное поведение, если функция действительно не пытается записать в массив.

1

Проблема const_cast всегда одна и та же - она ​​позволяет вам «нарушать правила», точно так же, как лить в void* - уверен, что вы можете это сделать, но вопрос в том, почему вы должны это делать?

В этом случае это, конечно, нормально, но вы должны спросить себя, почему вы не объявили size_t countZeroes(const int* array, size_t count) в первую очередь?

И как общее правило о const_cast:

  1. Это может привести к трудно найти ошибки
  2. Вы выбрасывая константный-соглашение с компилятором
  3. В основном ты превращаешься язык в нижний уровень.