Почему константная корректность специфична для C ++?

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

Сейчас я использовал несколько языков программирования, и одна вещь, которая меня беспокоит в C ++, - это понятие константной корректности. Такого понятия нет в Java, C #, Python, Ruby, Visual Basic и т. Д., Похоже, это очень специфично для C ++.

Прежде чем вы порекомендуете мне C ++ FAQ Lite, я прочитал его, и он меня не убеждает. Совершенно правильные, надежные программы все время пишутся на Python, и нет ключевого слова const или эквивалента. В Java и C # объекты могут быть объявлены как final (или const), но не существует константных функций-членов или константных параметров функций. Если функции не требуется изменять объект, она может использовать интерфейс, который предоставляет только доступ для чтения к объекту. Эту технику в равной степени можно использовать и в C ++. В двух реальных системах C ++, над которыми я работал, константа использовалась очень мало, и все работало нормально. Так что я далек от того, чтобы позволить константе загрязнять кодовую базу.

Мне интересно, что делает const в C ++ необходимой, в отличие от других языков программирования.

Пока что я видел только один случай, когда нужно использовать const :

#include <iostream>

struct Vector2 {
    int X;
    int Y;
};

void display(/* const */ Vector2& vect) {
    std::cout << vect.X << " " << vect.Y << std::endl;
}

int main() {
    display(Vector2());
}

Компиляция с закомментированной константой принимается Visual Studio, но с предупреждением C4239, использовано нестандартное расширение. Итак, если вы хотите синтаксической краткости передачи временных файлов, избегания копий и сохранения соответствия стандартам, вы должны передавать по константной ссылке, ни в коем случае. Тем не менее, это больше похоже на причуду, чем на фундаментальную причину.

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

Причина, по которой const работает в C ++, заключается в том, что вы можете отказаться от нее. Если бы вы не могли его выбросить, ваш мир был бы отстойным. Если вы объявляете метод, который принимает константу Bla, вы можете передать ему неконстантную Bla. Но если наоборот, нельзя. Если вы объявляете метод, который принимает неконстантный Bla, вы не можете передать ему const Bla. Итак, теперь вы застряли. Итак, вам постепенно понадобится константная версия всего, что не константно, и вы получите теневой мир. В C ++ это сходит с рук, потому что, как и все в C ++, совершенно необязательно, нужна вам эта проверка или нет. Вы можете просто отбросить константность, если она вам не нравится.

Андерс Хейлсберг (архитектор C #), Выбор дизайна CLR


person Asik    schedule 02.09.2009    source источник
comment
Хейлсберг не совсем прав (в общем, не доверяйте программистам, не работающим на C ++, рационализировать решения по дизайну на C ++. Это всегда заканчивается ошибкой). C ++ не позволяет вам свободно отказываться от константности. Если переменная объявлена ​​как константа, тогда она остается константой, и вам не разрешается отбрасывать константу. Но если вы возьмете неконстантный объект, который неявно будет преобразован в константу, тогда вам будет разрешено отбросить константу.   -  person jalf    schedule 03.09.2009
comment
Новый язык D имеет множество функциональных конструкций, таких как const в C ++. В настоящее время ООП переоценивают.   -  person GogaRieger    schedule 03.09.2009
comment
Я думаю, что Андерс прав: всегда можно отбросить const. Вам просто не разрешено писать в него, если объект действительно const. За свою короткую жизнь программиста на C ++ у меня был только один случай, когда мне нужно было отбросить константу (wxStyledTextCtrl имеет все GetXXX методы неконстантные!). Если бы C ++ не позволял мне это делать, я бы застрял в этом дерьмовом API и позволил бы ему заразить дизайн моего класса.   -  person Johannes Schaub - litb    schedule 03.09.2009
comment
Мне нравится концепция Д. Он имеет неизменяемый, что означает, что объект является константным. И у него есть const, чтобы сказать, что просто путь доступа является константой. Вот что мне не нравится в C ++: если там что-то константное, вы не знаете, является ли это просто выражением, обозначающим объект, или сам объект, а также по наследованию для выражения (и, к сожалению, вы не можете просмотреть выражение, чтобы узнать, какое из двух является const).   -  person Johannes Schaub - litb    schedule 03.09.2009
comment
Думаю, я слышал, как Джон Скит однажды рационализировал насчет const, и он сказал, что const для C # было бы нереалистично, или что-то в этом роде, потому что нужно было бы проверить, хочет ли он быть вообще полезным. Но проверка константности при каждом доступе на запись слишком дорога. C ++ может легко уйти, просто сказав, что это неопределенное поведение, в этом случае C # не может.   -  person Johannes Schaub - litb    schedule 03.09.2009
comment
Нет необходимости использовать const. Как и все возможности C ++, это инструмент, который вы можете использовать.   -  person Martin York    schedule 03.09.2009
comment
Немецкий - единственный язык, в котором есть одно слово, означающее «злорадство». Я говорю по-английски и прекрасно ладлю, не используя слова «злорадство». Я думаю, что это бессмысленно, и эксперт по английскому языку говорит, что даже по-немецки вы можете просто сказать Vergnügen über das Missgeschick beziehungsweise Unglück eines anderen. Почему он не прав? ;-)   -  person Steve Jessop    schedule 03.09.2009
comment
Другой вопрос по этому поводу: stackoverflow.com/questions/528122/   -  person Johannes Schaub - litb    schedule 03.09.2009
comment
хммм .. Я еще не понял const в C ++, но раньше я думал, что это похоже на ключевое слово final в java или readonly в C # (хотя я не думаю, что только чтение может применяться к аргументам функции). Я ошибся?   -  person Mel    schedule 09.07.2013
comment
Поскольку указатели и ссылки позволяют вам сделать параметры функции входами и / или выходами, информативно пометить параметры только для ввода как таковые с помощью const, т.е. в сигнатуре функции указано, что я обещаю не изменять это. Если параметр является ссылкой на класс, то его константные функции-члены могут быть вызваны внутри функции. Рассмотрим, например, memcpy (). Даже без имен параметров вы знаете, какой параметр есть какой. void * memcpy (void *, const void *, size_t);   -  person cp.engr    schedule 29.07.2015
comment
Следует отметить, что в реальной жизни попытка ввести константную корректность в любую существующую кодовую базу значительного размера, скорее всего, закончится настоящим кошмаром, тогда как при разработке с нуля может быть исключительно полезным для улучшения качества кода. и исключение возможных ям-падений.   -  person tofro    schedule 29.02.2016


Ответы (14)


Корректность констант дает два заметных преимущества C ++, о которых я могу думать, одно из которых делает его довольно уникальным.

  • Он позволяет распространять представления об изменяемых / неизменяемых данных, не требуя множества интерфейсов. Отдельные методы могут быть аннотированы относительно того, могут ли они выполняться на константных объектах, и компилятор обеспечивает это. Да, иногда это может быть проблемой, но если вы используете его последовательно и не используете const_cast, у вас есть проверенная компилятором безопасность в отношении изменяемых и неизменяемых данных.
  • Если объект или элемент данных const, компилятор может поместить его в постоянную память. Это особенно важно для встроенных систем. C ++ поддерживает это; немногие другие языки делают. Это также означает, что в общем случае вы не можете безопасно отбросить const, хотя на практике вы можете сделать это в большинстве сред.

C ++ - не единственный язык с константной корректностью или чем-то в этом роде. OCaml и Standard ML имеют схожую концепцию с разной терминологией, почти все данные неизменяемы (const), и когда вы хотите, чтобы что-то было изменяемым, вы используете другой тип (тип ref) для этого. Так что это просто уникально для C ++ в пределах его соседних языков.

Наконец, обратное направление: были времена, когда я хотел const в Java. final иногда недостаточно далеко до создания просто неизменяемых данных (особенно неизменяемых представлений изменяемых данных) и не хотят создавать интерфейсы. Посмотрите на поддержку коллекции Unmodifiable в Java API и тот факт, что она проверяет только во время выполнения, разрешена ли модификация для примера того, почему const полезна (или, по крайней мере, структура интерфейса должна быть углублена, чтобы иметь List и MutableList), есть нет причин, по которым попытка изменить неизменяемую структуру не может быть ошибкой типа компиляции.

person Michael Ekstrand    schedule 02.09.2009
comment
Спасибо, что обратились к моей точке зрения напрямую, это похоже на очень веские аргументы. +1. - person Asik; 03.09.2009
comment
Важным моментом здесь является то, что он позволяет вам выразить понятие неизменяемости, которое не может быть выражено на других языках (даже если это рекомендуется). - person David Rodríguez - dribeas; 03.09.2009
comment
на практике вы можете [безопасно отбросить const] в большинстве сред. Не совсем. UB изменения объекта, определенного как const, не ограничивается риском того, что он может быть в ПЗУ. Если вы пишете const int i = 1; mutate((int*)&i); std::cout << i;, то компилятору разрешается предположить, что ни mutate, ни что-либо еще в программе не вызывало UB, записывая в i. На практике вы ожидаете, что модификация будет либо соблюдена, либо безвредно проигнорирована для этого кода, но в целом все может пойти не так, если оптимизатор предположил что-то, что оказывается неверным. - person Steve Jessop; 15.03.2014
comment
+1 за вторую точку. (См. Также C99 Rationale.) Это единственная причина, по которой текущий конкретный const (только для чтения, а не constexpr) является встроенной функцией языка. Однако -1 за риск UB на практике - не стоит отключать оптимизацию на практике. Итак, +0. - person FrankHB; 31.07.2016
comment
Обратите внимание, что в аспекте системы типов могут быть и другие виды константной корректности, основанные на различных отношениях эквивалентности, например ключевые требования std::map. Некоторые другие виды оптимизации, такие как распространение констант или сворачивание констант, могут по-прежнему работать аналогичным образом для этих новых видов констант. Точно так же, но более конкретно, UB может снова иметь место для этих нарушений корректности const. Однако текущие языки все еще слишком слабы, чтобы их поддерживать (к сожалению, ключи стандартных ассоциативных контейнеров теперь всегда const-квалифицированы, даже если я могу гарантировать различную эквивалентность самостоятельно). - person FrankHB; 31.07.2016

Я не думаю, что кто-то утверждает, что const-корректность «необходима». Но опять же, занятия на самом деле не нужны, не так ли? То же самое и с пространствами имен, исключениями ... вы понимаете.

Постоянная корректность помогает обнаруживать ошибки во время компиляции, и поэтому это полезно.

person Nemanja Trifunovic    schedule 02.09.2009

const - это способ выразить что-то. Было бы полезно на любом языке, если бы вы считали важным выразить это. У них нет этой функции, потому что разработчики языка не сочли их полезными. Думаю, если бы эта функция была там, она была бы не менее полезной.

Я думаю об этом как о спецификациях на Java. Если они вам нравятся, вы, вероятно, захотите их на других языках. Но создатели других языков не думали, что это так важно.

person Lou Franco    schedule 02.09.2009
comment
Хорошая аналогия с проверенными исключениями - вы меня опередили! - person Richard Berg; 03.09.2009
comment
Это попадает в самую точку. Ключевое слово const дает программисту семантическое значение. Я ничего не меняю! - person Corey D; 03.09.2009

Что ж, мне потребовалось 6 лет, чтобы по-настоящему понять, но теперь я наконец могу ответить на свой вопрос.

Причина, по которой C ++ имеет "константную корректность", а Java, C # и т. Д. - нет, заключается в том, что C ++ поддерживает только типы значений, а эти другие языки поддерживают только или, по крайней мере, по умолчанию ссылочные типы.

Давайте посмотрим, как C #, язык, по умолчанию использующий ссылочные типы, работает с неизменяемостью, когда задействованы типы значений. Допустим, у вас есть изменяемый тип значения и другой тип, у которого есть поле только для чтения этого типа:

struct Vector {
    public int X { get; private set; }
    public int Y { get; private set; }
    public void Add(int x, int y) {
        X += x;
        Y += y;
    }
}

class Foo {
    readonly Vector _v;
    public void Add(int x, int y) => _v.Add(x, y);
    public override string ToString() => $"{_v.X} {_v.Y}";
}

void Main()
{
    var f = new Foo();
    f.Add(3, 4);
    Console.WriteLine(f);
}

Что должен делать этот код?

  1. не компилировать
  2. напечатать "3, 4"
  3. напечатать "0, 0"

Ответ №3. C # пытается учесть ваше ключевое слово «только для чтения», вызывая метод Add для выбрасываемой копии объекта. Это странно, да, но какие еще варианты есть? Если он вызывает метод исходного вектора, объект изменится, нарушив "доступность только для чтения" поля. Если он не компилируется, то члены типа значения, доступные только для чтения, довольно бесполезны, потому что вы не можете вызывать для них какие-либо методы из-за страха, что они могут изменить объект.

Если бы мы только могли обозначить, какие методы безопасно вызывать в экземплярах только для чтения ... Подождите, это именно то, что константные методы в C ++!

C # не беспокоится о методах const, потому что мы не так часто используем типы значений в C #; мы просто избегаем изменяемых типов значений (и объявляем их "злыми", см. 1, 2).

Кроме того, ссылочные типы не страдают от этой проблемы, потому что, когда вы помечаете переменную ссылочного типа как только для чтения, только для чтения является ссылка, а не сам объект. Это очень легко реализовать компилятору, он может пометить любое присвоение как ошибку компиляции, за исключением инициализации. Если все, что вы используете, - это ссылочные типы и все ваши поля и переменные доступны только для чтения, вы получите неизменность везде с небольшими синтаксическими затратами. F # работает именно так. Java избегает этой проблемы, просто не поддерживая определяемые пользователем типы значений.

В C ++ нет понятия «ссылочные типы», только «типы значений» (в C # -lingo); некоторые из этих типов значений могут быть указателями или ссылками, но, как и типы значений в C #, ни один из них не владеет своим хранилищем. Если бы C ++ обрабатывал "const" для своих типов так же, как C # рассматривал бы "только для чтения" для типов значений, это было бы очень запутанным, как демонстрирует приведенный выше пример, не говоря уже о неприятном взаимодействии с конструкторами копирования.

Таким образом, C ++ не создает одноразовую копию, потому что это создало бы бесконечную боль. Это также не запрещает вам вызывать какие-либо методы для членов, потому что, ну, тогда язык не был бы очень полезным. Но он все еще хочет иметь какое-то понятие «только для чтения» или «постоянство».

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

person Asik    schedule 27.08.2015

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

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

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

person Jeremy Friesner    schedule 02.09.2009

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

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

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

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

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

Это концепция, по которой мне больше не хватает при переходе на другие языки. Рассмотрим сценарий, в котором у вас есть класс C, который, среди прочего, имеет атрибут a типа A, который должен быть видимым для внешнего кода (пользователи вашего класса должны иметь возможность запрашивать некоторую информацию о a). Если тип A имеет какую-либо операцию изменения, то, чтобы пользовательский код не менял ваше внутреннее состояние, вы должны создать копию a и вернуть ее. Программист класса должен знать, что необходимо выполнить копирование, и должен выполнить (возможно, дорогое) копирование. С другой стороны, если бы вы могли выразить постоянство в языке, вы могли бы просто вернуть постоянную ссылку на объект (фактически ссылку на постоянное представление объекта) и просто вернуть внутренний элемент. Это позволит пользовательскому коду вызывать любой метод объекта, который проверяется как неизменяемый, тем самым сохраняя инварианты вашего класса.

Проблема / преимущество, все зависит от точки зрения, постоянства в том, что он вирусный. Когда вы предлагаете постоянную ссылку на объект, могут быть вызваны только те методы, которые помечены как неизменяемые, и вы должны сообщить компилятору, какой из методов имеет это свойство. Когда вы объявляете константу метода, вы сообщаете компилятору, что пользовательский код, вызывающий этот метод, сохранит состояние объекта. Когда вы определяете (реализуете) метод с постоянной подписью, компилятор напомнит вам о вашем обещании и фактически потребует, чтобы вы не изменяли данные внутри себя.

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

В этом контексте никогда не следует использовать const_cast ‹>, поскольку результаты могут привести вас в область неопределенного поведения (как с языковой точки зрения: объект может находиться в памяти только для чтения, так и с точки зрения программы : возможно, вы нарушаете инварианты в других классах). Но это, конечно, вы уже знаете, если читаете C ++ FAQ lite.

В качестве побочного примечания, ключевое слово final в Java действительно не имеет ничего общего с ключевым словом const в C ++, когда вы имеете дело со ссылками (в ссылках или указателях C ++). Ключевое слово final изменяет локальную переменную, на которую оно ссылается, будь то базовый тип или ссылка, но не является модификатором упомянутого объекта. То есть вы можете вызывать методы изменения через последнюю ссылку и, таким образом, вносить изменения в состояние упомянутого объекта. В C ++ ссылки всегда постоянны (вы можете привязать их к объекту / переменной только во время построения), а ключевое слово const изменяет то, как пользовательский код может работать с указанным объектом. (В случае указателей вы можете использовать ключевое слово const как для данных, так и для указателя: X const * const объявляет константный указатель на константу X)

person David Rodríguez - dribeas    schedule 02.09.2009
comment
Спасибо. Я не пришел, как вы говорите, из языка, в котором нет const; C ++ - мой самый знакомый язык. Я только что искал в другом месте и задавался вопросом, почему C ++ спроектирован таким, какой он есть. Я по-прежнему считаю, что определение интерфейсов - это более чистый и общий способ выражения любых ограничений доступа, чем ключевое слово const, которое распространяется на все, к чему прикасается, и имеет много разных значений в зависимости от контекста. - person Asik; 03.09.2009
comment
Я не могу согласиться с вами по поводу комментария. Прежде всего, если вы определили интерфейсы, эквивалентные const, вы бы переполнили множество интерфейсов (и виртуальных методов) только для достижения того же результата, и результат был бы таким же вирусным, как и ключевое слово const. Ключевое слово const распространяется на все из-за ограничения доступа, которое оно накладывает, а не из-за того, что оно является «волшебным» ключевым словом. Тогда я не совсем понимаю ваш последний пункт: «[const] имеет много разных значений в зависимости от контекста». У const есть только одно значение, или я что-то упускаю? - person David Rodríguez - dribeas; 03.09.2009

Если вы пишете программы для встраиваемых устройств с данными во FLASH или ROM, вы не можете жить без константности. Это дает вам возможность контролировать правильную обработку данных в разных типах памяти.

person chrmue    schedule 03.09.2009

Вы также хотите использовать const в методах, чтобы воспользоваться преимуществами оптимизации возвращаемого значения. См. Пункт 20 «Более эффективный C ++ Скотта Мейерса».

person count0    schedule 02.09.2009

Этот разговор и видео от < em> Herb Sutter объясняет новые коннотации const в отношении безопасности потоков.

Постоянство, возможно, не было тем, о чем вам приходилось слишком беспокоиться раньше, но с C ++ 11, если вы хотите писать поточно-ориентированный код, вам нужно понимать значение const и mutable

person chillitom    schedule 18.01.2013

В C, Java и C # вы можете узнать, посмотрев на сайт вызова, может ли переданный объект быть изменен функцией:

  • в Java вы знаете, что это определенно может быть.
  • в C вы знаете, что это может быть, только если есть '&' или эквивалент.
  • в C # вам также нужно сказать «ref» на сайте вызова.

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

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

person soru    schedule 02.09.2009

Андерс Хейлсберг (архитектор C #): ... Если вы объявляете метод, который принимает неконстантный Bla, вы не можете передать ему const Bla. Итак, теперь вы застряли. Итак, вам постепенно понадобится константная версия всего, что не константно, и вы получите теневой мир.

Итак, еще раз: если вы начали использовать «const» для некоторых методов, вы обычно вынуждены были использовать это в большей части вашего кода. Но время, затрачиваемое на поддержание (ввод, перекомпиляция при отсутствии некоторой константы и т. Д.) Константной корректности в коде кажется больше, чем на исправление возможных (очень редких) проблем, вызванных тем, что константная корректность вообще не используется. Таким образом, отсутствие поддержки константной корректности в современных языках (таких как Java, C #, Go и т. Д.) Может привести к небольшому сокращению времени разработки при том же качестве кода.

Билет запроса на расширение для реализации корректности констант существовал в Java Community Process с 1999 года, но был закрыт в 2005 году из-за вышеупомянутого «загрязнения констант», а также по причинам совместимости: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070

Хотя в языке C # нет константной конструкции корректности, аналогичные функции, возможно, скоро появятся в «Microsoft Code Contracts» (библиотека + инструменты статического анализа) для .NET Framework с использованием атрибутов [Pure] и [Immutable]: Чистые функции в C #

person Community    schedule 17.01.2013
comment
Если вы объявляете метод, который принимает неконстантный Bla, вы не можете передать ему const Bla. Итак, теперь вы застряли. Как же так? У вас есть объект, который вы не хотите менять. Почему вы хотите передать его методу, в подписи которого есть возможность изменить что-либо, переданное ему? В самом деле, вы ожидаете, что сможете объявить const int FOO = 42;, а затем сделать FOO++;? const - это просто гарантия того, что код не изменит значение, и позволяет компилятору помочь вам в этом. По моему опыту, корректность const сокращает общее время разработки. - person Rob K; 06.07.2015

На самом деле, это не совсем так.

В других языках, особенно в функциональных или гибридных языках, таких как Haskell, D, Rust и Scala, существует концепция изменчивости: переменные могут быть изменяемыми или неизменяемыми и обычно неизменяемыми по умолчанию.

Это позволяет вам (и вашему компилятору / интерпретатору) лучше рассуждать о функциях: если вы знаете, что функция принимает только неизменяемые аргументы, то вы знаете, что эта функция не является той, которая изменяет вашу переменную и вызывает ошибку.

C и C ++ делают нечто подобное с использованием const, за исключением того, что это гораздо менее надежная гарантия: неизменяемость не обеспечивается; функция, расположенная ниже по стеку вызовов, могла бы отбросить константу и изменить ваши данные, но это было бы преднамеренным нарушением контракта API. Таким образом, намерение или лучшая практика состоит в том, чтобы он работал так же, как неизменяемость в других языках.

С учетом всего сказанного, в C ++ 11 теперь есть собственно ключевое слово mutable, наряду с более ограниченным ключевым словом const.

person Community    schedule 18.04.2014
comment
mutable появился задолго до C ++ 11, и я не уверен, что это имеет отношение к тому, о чем вы думаете. Кроме того, принуждение кажется странным, потому что в C ++ почти ничто не требует такого строгого соблюдения; например если я объявляю int x;, нет ничего, что навязывало бы идею о том, что x хранит объект int, поскольку я могу отбросить и это. - person ; 06.07.2015

Ключевое слово const в C ++ (применительно к параметрам и объявлениям типов) - это попытка удержать программистов от того, чтобы они не оттолкнули себя и не вырубили себе при этом всю ногу.

Основная идея состоит в том, чтобы пометить что-либо как «не может быть изменено». Тип const нельзя изменить (по умолчанию). Константный указатель не может указывать на новое место в памяти. Все просто, правда?

Что ж, вот где появляется корректность const. Вот некоторые из возможных комбинаций, в которых вы можете оказаться при использовании const:

Постоянная переменная. Подразумевает, что данные, помеченные именем переменной, не могут быть изменены.

Указатель на константную переменную Подразумевает, что указатель может быть изменен, но сами данные - нет.

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

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

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

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

person Randolpho    schedule 02.09.2009

Например, у вас есть функция:

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

Другой способ

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

В основном:

int main(int argc, char **argv)
{
    const_print("Hello");
    print("Hello");        // syntax error
}

Это потому, что "hello" - это указатель const char, строка (в стиле C) помещается в постоянную память. Но в целом это полезно, когда программист знает, что значение не будет изменено, чтобы получить ошибку компилятора вместо ошибки сегментации. Как в нежелательных заданиях:

const int a;
int b;
if(a=b) {;} //for mistake

Поскольку левый операнд - это const int.

person Ramy Al Zuhouri    schedule 16.02.2012
comment
К сожалению, из соображений обратной совместимости существует (устаревшая) лазейка, в которой строковый литерал может быть передан в char*, так что вашей синтаксической ошибки на самом деле нет. - person ; 06.07.2015