2013-08-05 2 views
18

Есть ли другая защита от их модификации?Переменные константы помещаются в постоянное запоминающее устройство?

Имеет смысл, если они находятся в памяти только для чтения - вот почему их создание const, верно?

+5

См. [Этот ответ] (http://stackoverflow.com/a/4486356/420683) для примера 'const volatile', где память только для чтения не имеет смысла. – dyp

+0

Я почти уверен, что в C# все применения 'const' заменяются их значением во время компиляции, поэтому ничего не осталось изменить. Я не знаю, является ли это .NET-ism, или если он унаследован от C. – Bobson

+3

@Bobson Это невозможно достичь в C++, потому что переменные 'const' могут иметь значение, установленное во время выполнения. – juanchopanza

ответ

15

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

+2

«Компилятор выполнит его», я полагаю, вы предполагаете, что вы ожидаете, что компилятор выдает диагностику, если исходный код пытается изменить объект с помощью типа, соответствующего const, а не что компилятор не позволит вам преобразовать тип, определенный с помощью константы (или указатели к такому), к типу, не содержащему константы (или указателям на него) и модификации объекта через неконстантный тип, если такая модификация разрешена стандарт C++ (как это бывает в некоторых ситуациях)? –

2

Что касается стандарта, то нет необходимости вставлять переменные const в ОЗУ с защитой от записи. const - это в основном только документация, связанная с компилятором.

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

12

Нет, они не обязаны быть. const - это время компиляции и позволяет компилятору выполнять некоторую оптимизацию. Однако необязательно, чтобы переменная была помещена в ячейку памяти только для чтения.

Смотрите этот пример, который Неопределенное поведение (Спасибо DYP за указание, что выход):

#include <iostream> 

int  main() 
{ 
    const int bla = 42; 
    int  *ptr = const_cast<int *>(&bla); 

    std::cout << *ptr << std::endl; 
    *ptr = 21; 
    std::cout << *ptr << std::endl; 
} 

Он будет выводить 42 и 21, но это также может произойти сбой.

Теперь увидеть это один:

#include <iostream> 

int  main() 
{ 
    const int bla = 42; 
    int  *ptr = const_cast<int *>(&bla); 

    std::cout << bla << std::endl; 
    *ptr = 21; 
    std::cout << bla << std::endl; 
} 

На мой компилятор, этот выход 42 и 42, потому что компилятор сделал некоторые оптимизации. Обратите внимание, что он все равно может потерпеть крах из-за *ptr = 21;

+0

'* ptr = 21;' Неопределенное поведение. – dyp

+0

@ DyP Отредактировано. Не могли бы вы дать мне объяснения или ссылки, объясняющие с помощью '* ptr = 21' UB? Не является ли 'const_cast' допустимой конструкцией, которая позволила бы изменить переменную? – Xaqq

+0

Это позволяет вам изменять переменную *, если эта переменная не была объявлена ​​'const' *. В противном случае UB: [dcl.type.cv]/4 "За исключением того, что любой член класса, объявленный' mutable', может быть изменен, любая попытка изменить объект 'const' в течение его жизненного цикла приводит к неопределенному поведению." – dyp

2

Нет. Рассмотрим объект const с членом mutable. Как упоминалось, const представляет собой конструкцию времени компиляции, чтобы помочь программисту передать намерение.

1

Если бы они были в памяти только для чтения, это помешало бы const_cast быть полезными и значимыми, поэтому код, как это было бы невозможно, минуя const переменных функции с непостоянным const параметра: -

void print (char * str) 
{ 
    cout << str << endl; 
} 

int main() 
{ 
    const char * c = "test text"; 
    print (const_cast<char *> (c)); 
    return 0; 
} 

Обратите внимание, что функция печати может фактически изменить значение в первоначально определенной переменной constc.

+2

«Обратите внимание, что функция печати может фактически изменить значение в первоначально заданной константной переменной c": но это может привести к сбою программы. – Xaqq

+0

Абсолютно, хотя это зависит от того, что произошло. Если он просто убирает строку или удерживает ее в пределах длины строки, тогда это будет нормально. Поэтому он «может» изменить его, но, вероятно, не должен. – TheDarkKnight

+3

'const_cast' на самом деле полезен для отбрасывания константы, которая была добавлена, например' char c = 'x'; char const & crc = c; char & rc = const_cast (crc); '(обычно с использованием параметров функции). – dyp

5

Существует много случаев, когда компилятор не может сделать const в постоянное запоминающее устройство (при условии, что в системе в первую очередь имеется постоянная память). На самом деле, я считаю, что почти все компиляторы, как правило, создают объекты const в обычной памяти данных (или стека), как и обычные переменные.

Основная цель const состоит в том, чтобы объявить о своем намерении компилятором, которого вы не хотите, и не должны изменять какое-либо значение.Я не вижу причин, по которым компиляторы не могут при ограниченных обстоятельствах помещать переменные const в постоянную память. Но я также не стал бы полагаться на это - стандарт, безусловно, делает это возможным, поскольку в нем упоминается, что с помощью const_cast удалите const с объекта, который был первоначально отмечен const, а затем писать ему неопределенное поведение (поэтому он не требует компилятор, чтобы позволить изменять значение после использования const_cast для удаления оригинала const - и, таким образом, это разрешает «Сбой, потому что мы пытались записать в постоянную память»).

Но подумайте:

class X 
{ 
    int x; 
    public: 
    X(int v) : x(v) {} 
} 

int c = rand(); 

const X a(c+1); 
const X b(c+2); 

В этом случае компилятор не может знать значение c, что получил от rand, поэтому он не может инициализировать a и b во время компиляции.

+0

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

+0

Хорошо :) но я все еще могу быть педантичным: 'char c; char const & rc = c; '->' rc' также является переменной и объявляется 'const'. – dyp

+0

Не уверен, что я понимаю ваш педантизм. 'rc' является ссылкой' const' на 'c', поэтому та же переменная, что и' c' - в этом случае, она действительна для 'const_cast' способом constness и записывается в ссылку, изменяя, таким образом, исходное значение' c '. –

2

const ключевого слово имеет два применения:

  1. Известные «Я обещаю не изменять состояние этого объекта»
  2. в качестве специальной нормы, компилятор может место объектов, определение const в постоянной памяти, пока объект не имеет элементов mutable (т. е. весь объект является состоянием объекта).

Именно поэтому const_cast IST разрешается стирает константный спецификатор, но требование состоит в том, что определение объекта сам по себе не const. Wikipedia on const correctness гласит: «Однако любая попытка изменить объект, который сам объявляет const с помощью const_cast, приводит к неопределенному поведению в соответствии со стандартом ISO C++».

+0

" Вот почему 'const_cast' разрешено отбрасывать классификатор' const'. Я думаю, вы имеете в виду правильную вещь, но это выглядит как (2.), поэтому эта причина (а это не так). Бонус: вот цитата для UB прямо из Стандарта: [dcl.type.cv]/4 "За исключением того, что любой член класса, объявленный mutable, может быть изменен, любая попытка изменить объект' const' в течение его жизненного цикла приводит к неопределенному поведению. " – dyp

2

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

Было бы сложно реализовать объекты на C++ const с автоматическим временем хранения, адреса которого записываются в постоянное запоминающее устройство. Это связано с тем, что каждый другой объект должен иметь другой адрес (потому что их указатели должны сравнивать неравные). Поэтому каждый такой объект должен быть создан каждый раз, когда выполняется его блок.

Если объект объекта const не принят, компилятор может реализовать несколько экземпляров его (в вычислительной модели C++), используя только один экземпляр в памяти (поскольку каждый экземпляр идентичен и не изменяется). Таким образом, такой объект может быть создан один раз при запуске программы (вероятно, при загрузке из секции с постоянными данными в файле программы), помеченном только для чтения и оставлен без изменений в течение всего времени выполнения программы. Однако, если адрес объекта принимается (и используется видимыми способами), то компилятор должен создать каждый отдельный экземпляр объекта (или как-то «поддельный», который имеет один экземпляр с несколькими адресами). В общем, компилятор не может предсказать, сколько одновременных исполнений блока может существовать одновременно (например, когда есть рекурсивные вызовы функций). Поэтому при запуске программы он не может создать все экземпляры требуемого объекта. Они должны создаваться «на лету».

Создание объектов требует изменения памяти, чтобы записать начальные значения объектов. Таким образом, помещение объектов с автоматическим хранением в памяти только для чтения потребует частое изменение памяти от чтения до записи и обратно.Чтобы создать новый объект, программе пришлось бы изменить постоянное запоминающее устройство на записываемую память, записать начальное значение нового объекта и изменить память на «только для чтения».

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

1

const - знак для компилятора. Во время компиляции компилятор добавляет константы в отдельную группу и проверяет попытки ее изменения. Если какая-то функция пытается это сделать, вы получите ошибку компилятора.

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

Как я уже сказал, моему другу, который смотрел, как изменить const значение. const предназначен не только для компилятора, но и для разработчика, а затем для компилятора, потому что он показывает, какие данные не будут изменены.

Смежные вопросы