Как далеко вы идете с const
? Вы просто делаете функцииconst
когда это необходимо, или вы идете на всю свинью и используете ее везде? Например, представьте себе простой мутатор, который принимает один логический параметр:
void SetValue(const bool b) { my_val_ = b; }
В том, что const
действительно полезно? Лично я предпочитаю использовать его широко, включая параметры, но в этом случае мне интересно, стоит ли это?
Я также был удивлен, узнав, что вы можете опустить const
параметры в объявлении функции, но можете включить их в определение функции, например:
.h файл
void func(int n, long l);
файл .cpp
void func(const int n, const long l)
Есть причина для этого? Это кажется немного необычным для меня.
Ответы:
Причина в том, что const для параметра применяется только локально внутри функции, поскольку он работает с копией данных. Это означает, что сигнатура функции в любом случае действительно одинакова. Это, вероятно, плохой стиль, чтобы делать это много, хотя.
Лично я склонен не использовать const за исключением параметров ссылки и указателя. Для скопированных объектов это на самом деле не имеет значения, хотя может быть более безопасным, поскольку сигнализирует о намерениях внутри функции. Это действительно суждение. Однако я склонен использовать const_iterator, когда зацикливаюсь на чем-то, и я не собираюсь его модифицировать, поэтому я предполагаю, что каждый из них сам по себе, до тех пор, пока строго соблюдается правильность констант для ссылочных типов.
источник
const
из прототипов функций имеет то преимущество , что вам не нужно , чтобы изменить файл заголовок , если вы решили отказатьсяconst
от части реализации позже.const
там, где это имеет полезное значение».const
когда это возможно; это более выразительно. Когда я читаю чужой код, я использую маленькие индикаторы, подобные этому, чтобы судить, насколько тщательно они уделяют написанию своего кода наряду с такими вещами, как магические числа, комментарии, правильное использование указателей и т. Д.int getDouble(int a){ ++a; return 2*a; }
Попробуй это. Конечно, там++a
нечего делать, но это можно найти в длинной функции, написанной более чем одним программистом в течение длительного периода времени. Я настоятельно рекомендую написать,int getDouble( const int a ){ //... }
что при поиске будет сгенерирована ошибка компиляции++a;
.class Foo { int multiply(int a, int b) const; }
в шапке. В вашей реализации вы делаете уход , что вы можете обещать не изменятьa
иb
поэтомуint Foo::multiply(const int a, const int b) const { }
имеет смысл здесь. (Замечание: и вызывающая сторона, и реализация заботятся о том, чтобы функция не изменяла свойFoo
объект, то есть const в конце своего объявления)«const не имеет смысла, когда аргумент передается по значению, так как вы не будете изменять объект вызывающего».
Неправильно.
Речь идет о самодокументировании вашего кода и ваших предположений.
Если в вашем коде работает много людей, а ваши функции нетривиальны, то вы должны пометить «const» любым и всем, что можете. При написании кода промышленного уровня вы всегда должны исходить из того, что ваши коллеги - психопаты, пытающиеся помочь вам любым доступным способом (тем более что это часто происходит в будущем).
Кроме того, как кто-то упоминал ранее, это может помочь компилятору немного оптимизировать вещи (хотя это далеко).
источник
Иногда (слишком часто!) Мне приходится распутывать чужой код C ++. И мы все знаем, что чей-то код на C ++ является полным беспорядком почти по определению :) Поэтому первое, что я делаю для расшифровки локального потока данных, это помещаю const в каждое определение переменной, пока компилятор не начнет лаять. Это также означает аргументы значения, соответствующие определению констант, потому что они являются просто причудливыми локальными переменными, инициализированными вызывающей стороной.
Ах, я хочу переменные были Const по умолчанию и изменяемые требуется для неконстантных переменных :)
источник
[x](){return ++x;}
- это ошибка; смотрите здесьconst
по умолчанию "" в Rust :)Следующие две строки функционально эквивалентны:
Очевидно, что вы не сможете изменить
a
тело,foo
если оно определено вторым способом, но снаружи нет никакой разницы.Что
const
действительно пригодится, так это параметры ссылки или указателя:Это говорит о том, что foo может принимать большой параметр, возможно, структуру данных размером в гигабайты, не копируя его. Кроме того, он говорит вызывающей стороне: «Foo не * изменит содержимое этого параметра». Передача константной ссылки также позволяет компилятору принимать определенные решения о производительности.
*: Если это не отбрасывает постоянство, но это другой пост.
источник
Слишком много лишних const плохо с точки зрения API:
Добавление в ваш код лишних констант для параметров внутреннего типа, передаваемых по значению, загромождает ваш API , не давая никаких значимых обещаний вызывающей стороне или пользователю API (это только мешает реализации).
Слишком много «const» в API, когда оно не нужно, похоже на « плачущего волка », в конце концов, люди начнут игнорировать «const», потому что он повсюду и ничего не значит в большинстве случаев.
Аргумент "reductio ad absurdum" к дополнительным концам в API хорош для этих первых двух пунктов: если больше параметров const хороши, то каждый аргумент, который может иметь const, ДОЛЖЕН иметь const на нем. На самом деле, если бы это было действительно так хорошо, вы бы хотели, чтобы const был параметром по умолчанию для параметров и имел бы ключевое слово типа «изменяемый» только тогда, когда вы хотите изменить параметр.
Итак, давайте попробуем положить в const, где мы можем:
Рассмотрим строку кода выше. Не только объявление более загромождено, длиннее и труднее для чтения, но и пользователь API может безопасно игнорировать три из четырех ключевых слов «const». Однако дополнительное использование const сделало вторую строку потенциально ОПАСНОЙ!
Почему?
Быстрое неверное прочтение первого параметра
char * const buffer
может заставить вас подумать, что он не изменит память в буфере данных, который передается, однако это не так! Избыточное «const» может привести к опасным и неверным предположениям о вашем API при сканировании или неправильном прочтении.Лишние const также плохи с точки зрения реализации кода:
Если FLEXIBLE_IMPLEMENTATION не соответствует действительности, то API «обещает» не реализовывать функцию первым способом ниже.
Это очень глупое обещание. Почему вы должны давать обещание, которое не приносит никакой пользы вашему абоненту и только ограничивает вашу реализацию?
Обе они являются совершенно правильными реализациями одной и той же функции, хотя все, что вы сделали, - это без необходимости связали одну руку за спиной.
Кроме того, это очень поверхностное обещание, которое легко (и юридически обойдется).
Послушай, я все-таки реализовал это так, хотя обещал не делать этого, просто используя функцию-обертку. Это как когда плохой парень обещает не убивать кого-то в фильме и приказывает своему приспешнику убить их.
Эти лишние консты стоят не больше, чем обещание плохого парня из фильма.
Но способность лгать становится еще хуже
Я понял, что вы можете не соответствовать const в заголовке (объявление) и коде (определение) с помощью ложного const. Адвокаты, довольные константой, утверждают, что это хорошо, так как позволяет использовать констант только в определении.
Тем не менее, обратное утверждение верно ... вы можете поместить ложный констант только в объявлении и игнорировать его в определении. Это только делает излишнее const в API более ужасной вещью и ужасной ложью - см. Этот пример:
Все, что на самом деле делает лишнее const - это делает код разработчика менее читаемым, заставляя его использовать другую локальную копию или функцию-обертку, когда он хочет изменить переменную или передать переменную по неконстантной ссылке.
Посмотрите на этот пример. Что является более читабельным? Очевидно ли, что единственная причина для дополнительной переменной во второй функции заключается в том, что какой-то разработчик API добавил лишнее const?
Надеюсь, мы кое-что узнали здесь. Лишний const - это загромождение API, раздражающее раздражение, поверхностное и бессмысленное обещание, ненужное препятствие и иногда приводящее к очень опасным ошибкам.
источник
void foo(int)
иvoid foo(const int)
является точно такой же функцией, а не перегрузками. ideone.com/npN4W4 ideone.com/tZav9R Здесь const является лишь подробностью реализации тела функции и не влияет на разрешение перегрузки. Оставьте const вне объявления для более безопасного и аккуратного API, но добавьте const в определение , если вы не собираетесь изменять скопированное значение.pi++
компонентами, не допускают ошибок, например, когда они не должны этого делать.const должен был быть по умолчанию в C ++. Нравится :
источник
unsigned
должно было быть по умолчанию в C ++. Как это:int i = 5; // i is unsigned
иsigned int i = 5; // i is signed
.Когда я кодировал C ++ для жизни, я использовал все, что мог. Использование const - отличный способ помочь компилятору помочь вам. Например, использование возвращаемых значений вашего метода может спасти вас от опечаток, таких как:
когда вы имели в виду:
Если функция foo () определена для возврата неконстантной ссылки:
Компилятор с радостью позволит вам присвоить значение анонимному временному объекту, возвращаемому вызовом функции. Делая это const:
Устраняет эту возможность.
источник
foo() = 42
: error: lvalue требуется в качестве левого операнда присваиванияconst int foo()
это другой тип, чемint foo()
, который доставляет вам большие неприятности, если вы используете такие вещи, как указатели функций, системы сигналов / слотов или boost :: bind.const int& foo()
то же самоеint foo()
, что из-за оптимизации возвращаемого значения?На эту тему есть хорошее обсуждение в старых статьях "Гуру недели" на comp.lang.c ++., Модерируемых здесь .
Соответствующая статья GOTW доступна на веб-сайте Херба Саттера здесь .
источник
Я говорю const ваши значения параметров.
Рассмотрим эту функцию с ошибками:
Если бы параметр number был const, компилятор остановился бы и предупредил нас об ошибке.
источник
Я использую const для параметров функции, которые являются ссылками (или указателями), которые являются только [in] данными и не будут изменены функцией. Это означает, что когда цель использования ссылки состоит в том, чтобы избежать копирования данных и не допустить изменения переданного параметра.
Помещение const в логический параметр b в вашем примере только накладывает ограничение на реализацию и не влияет на интерфейс класса (хотя обычно рекомендуется не изменять параметры).
Подпись функции для
а также
то же самое, что объясняет ваши .c и .h
Асаф
источник
Если вы используете операторы
->*
или.*
, это обязательно.Это мешает вам написать что-то вроде
что я почти сделал прямо сейчас, и который, вероятно, не делает то, что вы собираетесь.
То, что я хотел сказать, было
и если бы я поставил
const
междуBar *
иp
, компилятор сказал бы мне это.источник
Ах, тяжелый. С одной стороны, объявление является контрактом, и в действительности не имеет смысла передавать константный аргумент по значению. С другой стороны, если вы посмотрите на реализацию функции, вы дадите компилятору больше возможностей для оптимизации, если объявите константу аргумента.
источник
const не имеет смысла, когда аргумент передается по значению, так как вы не будете изменять объект вызывающей стороны.
const должен быть предпочтительным при передаче по ссылке, если только целью функции не является изменение переданного значения.
Наконец, функция, которая не изменяет текущий объект (this), может и, вероятно, должна быть объявлена как const. Пример ниже:
Это обещание не изменять объект, к которому применяется этот вызов. Другими словами, вы можете позвонить:
Если функция не является константой, это приведет к предупреждению компилятора.
источник
Маркировка значений параметров «const» - определенно субъективная вещь.
Однако я предпочитаю отмечать значения параметров const, как в вашем примере.
Значение для меня ясно указывает на то, что значения параметров функции никогда не меняются функцией. Они будут иметь то же значение в начале, что и в конце. Для меня это часть сохранения стиля функционального программирования.
Для короткой функции, возможно, это пустая трата времени / пространства, чтобы иметь «const», поскольку обычно довольно очевидно, что аргументы не модифицируются функцией.
Однако для более крупной функции это форма документации по реализации, и она обеспечивается компилятором.
Я могу быть уверен, что если я сделаю какое-то вычисление с 'n' и 'l', я смогу реорганизовать / переместить это вычисление, не боясь получить другой результат, потому что я пропустил место, где один или оба изменены.
Поскольку это деталь реализации, вам не нужно объявлять параметры-значения const в заголовке, точно так же, как вам не нужно объявлять параметры функции с теми же именами, что и в реализации.
источник
Может быть, это не будет действительным аргументом. но если мы увеличим значение переменной const внутри компилятора функции, то получим ошибку: « ошибка: приращение параметра только для чтения ». так что это означает, что мы можем использовать ключевое слово const как способ предотвратить случайное изменение наших переменных внутри функций (которые мы не должны использовать только для чтения). так что если мы случайно сделали это во время компиляции, компилятор сообщит нам об этом. это особенно важно, если вы не единственный, кто работает над этим проектом.
источник
Я склонен использовать const везде, где это возможно. (Или другое подходящее ключевое слово для целевого языка.) Я делаю это исключительно потому, что он позволяет компилятору делать дополнительные оптимизации, которые он не смог бы сделать иначе. Поскольку я понятия не имею, что это за оптимизация, я всегда делаю это, даже если это кажется глупым.
Насколько я знаю, компилятор мог бы очень хорошо видеть параметр константного значения и сказать: «Эй, эта функция все равно не изменяет его, поэтому я могу перейти по ссылке и сохранить некоторые тактовые циклы». Я не думаю, что это когда-либо сделало бы такую вещь, так как это изменяет сигнатуру функции, но это имеет значение. Может быть, он выполняет какие-то другие манипуляции со стеком или что-то в этом роде ... Дело в том, что я не знаю, но я знаю, что попытка быть умнее компилятора только приводит к тому, что мне стыдно.
С ++ имеет дополнительный багаж с идеей правильности, поэтому он становится еще более важным.
источник
const
. Скорее, это вопрос определения намерения в реализации и последующего перехвата мыслей (случайное увеличение неправильной локальной переменной, потому что это не такconst
). Параллельно, я бы также добавил, что компиляторы могут изменять сигнатуры функций в том смысле, что функции могут быть встроенными, а однажды встроенными может быть изменен весь способ их работы; добавление или удаление ссылок, создание литералов «переменных» и т. д. находятся в рамках правила «как если бы»1. Лучший ответ на основе моей оценки:
Ответ @Adisak - лучший ответ, основанный на моей оценке. Обратите внимание , что этот ответ отчасти лучше , потому что это также наиболее хорошо резервируется с реальными примерами кода , в дополнение к использованию звука и хорошо продуманную логику.
2. Мои собственные слова (согласен с лучшим ответом):
const
. Все, что он делает, это:const
везде может помешать этому.const
ненужного загромождает код сconst
s везде, отвлекая внимание отconst
s, которые действительно необходимы для безопасного кода.const
это критически важно при необходимости и должно использоваться, так как оно предотвращает нежелательные побочные эффекты с постоянными изменениями вне функции, и поэтому каждый отдельный указатель или ссылка должны использоваться,const
когда параметр является только входом, не выход. Использованиеconst
только параметров, передаваемых по ссылке или указателю, дает дополнительное преимущество, так как делает очевидным, какие параметры являются указателями или ссылками. Это еще одна вещь, которую нужно выделить и сказать: «Берегись! Любой параметрconst
рядом с ним - это ссылка или указатель!».3. Слова Google (согласен со мной и лучший ответ):
(Из « Руководства по стилю Google C ++ »)
Источник: раздел «Использование const» в Руководстве по стилю Google C ++: https://google.github.io/styleguide/cppguide.html#Use_of_const . Это действительно очень ценный раздел, поэтому прочитайте весь раздел.
Обратите внимание, что "TotW # 109" означает "Совет недели # 109: значимый
const
в объявлениях функций" , а также является полезным чтением. Он более информативен и менее директивен в отношении того, что делать, и на основе контекста появился до того,const
как вышеприведенное правило «Руководства по стилю Google C ++» было приведено выше, но из-за его ясностиconst
приведенное выше правило было добавлено в Google C ++. Гид по стилю.Также обратите внимание, что хотя я цитирую Руководство по стилю Google C ++ здесь в защиту своей позиции, это НЕ означает, что я всегда следую этому руководству или всегда рекомендую следовать этому руководству. Некоторые из вещей , которые они рекомендуют являются просто странны, такими , как их
kDaysInAWeek
-style именования для «Постоянных имен» . Тем не менее, тем не менее, полезно и уместно указать, что одна из самых успешных и влиятельных в мире технических и программных компаний использует то же обоснование, что и я, и другие, такие как @Adisak, чтобы поддержать наши взгляды на этот вопрос.4. У Кланга Линтера
clang-tidy
есть несколько вариантов:A. Кроме того , стоит отметить , что ЛИНТЕР звона, в
clang-tidy
, имеет вариант,readability-avoid-const-params-in-decls
, описанные здесь , чтобы поддержать исполнение в кодовой базе не используяconst
для передачи по значению параметров функции :И вот еще два примера, которые я добавляю себе для полноты и ясности:
Б. У этого также есть эта опция:
readability-const-return-type
- https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html5. Мой прагматичный подход к тому, как я бы сформулировал руководство по стилю по этому вопросу:
Я просто скопировал бы и вставил это в мое руководство по стилю:
[КОПИЯ / НАЧАЛО СТРАНИЦЫ]
const
параметры функции, передаваемые по ссылке или указателю, когда их содержимое (на что они указывают) НЕ предназначены для изменения. Таким образом, это становится очевидным, когда переменная, переданная по ссылке или указателю, ожидается изменить, потому что она будет отсутствоватьconst
. В этом случае использованияconst
предотвращает случайные побочные эффекты за пределами функции.const
на параметры функции передаются по значению, потому чтоconst
не имеет никакого влияния на вызывающей: даже если переменная изменяется в функции не будет никаких побочных эффектов за пределами функции. См. Следующие ресурсы для дополнительного обоснования и понимания:const
в объявлениях функций»const
[то есть:const
для параметров, передаваемых по значению ], для параметров функции в объявлениях, которые не являются определениями (и будьте осторожны, чтобы не копировать / вставлять бессмысленныеconst
). Это бессмысленно и игнорируется компилятором, это визуальный шум и это может ввести читателей в заблуждение »( https://abseil.io/tips/109 , выделение текста добавлено).const
квалификаторы, которые влияют на компиляцию, это те, которые помещены в определение функции, а НЕ в предварительное объявление функции, например в объявление функции (метода) в заголовочном файле.const
[то есть:const
для переменных, переданных по значению ] для значений, возвращаемых функцией.const
указателей или ссылок, возвращаемых функцией, зависит от разработчика , поскольку это иногда полезно.clang-tidy
параметров:Вот несколько примеров кода, демонстрирующих
const
правила, описанные выше:const
Примеры параметров:(некоторые заимствованы отсюда )
const
Примеры типов возвращаемых данных:(некоторые заимствованы отсюда )
[КОПИЯ / ВСТАВИТЬ КОНЕЦ]
источник
В случае, если вы упомянули, это не влияет на абонентов вашего API, поэтому это обычно не делается (и не обязательно в заголовке). Это влияет только на реализацию вашей функции.
Это не так уж плохо, но преимущества не так велики, учитывая, что они не влияют на ваш API, и добавляют типографию, поэтому обычно это не делается.
источник
Я не использую const для переданного значения параметра. Вызывающей стороне не важно, измените ли вы параметр или нет, это детали реализации.
Что действительно важно, так это пометить методы как const, если они не изменяют свой экземпляр. Делайте это по ходу дела, потому что в противном случае вы можете получить либо много const_cast <>, либо вы можете обнаружить, что маркировка метода const требует изменения большого количества кода, потому что он вызывает другие методы, которые должны были быть помечены как const.
Я также склонен отмечать локальные переменные const, если мне не нужно их изменять. Я считаю, что это облегчает понимание кода, облегчая идентификацию «движущихся частей».
источник
По оптимизации компилятора: http://www.gotw.ca/gotw/081.htm
источник
Я использую const, где могу. Const для параметров означает, что они не должны изменять свое значение. Это особенно ценно при передаче по ссылке. const for function объявляет, что функция не должна изменять членов классов.
источник
Обобщить:
std::vector::at(size_type pos)
. То, что достаточно для стандартной библиотеки, хорошо для меня.источник
_Tmp
всегда - вы этого не хотите (на самом деле вы не можете их использовать).Если параметр передается по значению (и не является ссылкой), обычно нет большой разницы, объявлен ли параметр как const или нет (если он не содержит элемент ссылки - не проблема для встроенных типов). Если параметр является ссылкой или указателем, обычно лучше защищать ссылочную / указанную память, а не сам указатель (я думаю, что вы не можете сделать ссылку самой константой, не то чтобы она имела большое значение, так как вы не можете изменить рефери) , Кажется, это хорошая идея, чтобы защитить все, что вы можете, как const. Вы можете опустить его, не опасаясь ошибиться, если параметры - это просто POD (включая встроенные типы), и нет никаких шансов на их дальнейшее изменение по дороге (например, в вашем примере - параметр bool).
Я не знал о разнице в объявлении файла .h / .cpp, но в этом есть какой-то смысл. На уровне машинного кода ничто не является «const», поэтому, если вы объявляете функцию (в .h) как неконстантную, код такой же, как если бы вы объявляли ее как const (без оптимизации). Тем не менее, это поможет вам подключить компилятор, чтобы вы не меняли значение переменной внутри реализации функции (.ccp). Это может пригодиться в том случае, если вы наследуете интерфейс, который позволяет вносить изменения, но вам не нужно менять параметр для достижения требуемой функциональности.
источник
Я бы не стал использовать const для таких параметров - все уже знают, что логическое значение (в отличие от логического &) является константой, поэтому добавление его заставит людей подумать «подождите, что?» или даже что вы передаете параметр по ссылке.
источник
Что нужно помнить с помощью const, так это то, что с самого начала сделать вещи проще, чем пытаться вставить их позже.
Используйте const, когда вы хотите, чтобы что-то не изменилось - это дополнительная подсказка, которая описывает, что делает ваша функция и чего ожидать. Я видел много C API, которые могли бы с некоторыми из них, особенно те, которые принимают c-строки!
Я был бы более склонен опустить ключевое слово const в файле cpp, чем заголовок, но, поскольку я склонен их вырезать и вставить, они будут храниться в обоих местах. Я понятия не имею, почему компилятор позволяет это, я думаю, это вещь компилятора. Лучше всего указывать ключевое слово const в обоих файлах.
источник
На самом деле нет смысла делать параметр-значение «const», так как функция все равно может только изменять копию переменной.
Причиной использования «const» является то, что вы передаете что-то большее (например, структуру с большим количеством членов) по ссылке, и в этом случае это гарантирует, что функция не сможет ее изменить; вернее, компилятор будет жаловаться, если вы попытаетесь изменить его обычным способом. Это предотвращает его случайное изменение.
источник
Параметр Const полезен только тогда, когда параметр передается по ссылке, т. Е. По ссылке или по указателю. Когда компилятор видит параметр const, он проверяет, что переменная, используемая в параметре, не изменяется в теле функции. Почему кто-то хочет сделать параметр по значению как константу? :-)
источник
const
ясно говорит: «Мне не нужно изменять это, поэтому я заявляю об этом. Если я попытаюсь изменить его позже, выдайте мне ошибку во время компиляции, чтобы я мог исправить свою ошибку или снять пометку какconst
. ' Так что это вопрос гигиены кода и безопасности. Для всего, что нужно, чтобы добавить к файлам реализации, это должно быть то, что люди делают как чистый рефлекс, IMO.Поскольку параметры передаются по значению, это не имеет никакого значения, если вы указываете const или нет с точки зрения вызывающей функции. По сути, нет никакого смысла объявлять параметры передачи по значению как const.
источник
Все минусы в ваших примерах не имеют смысла. C ++ по умолчанию передается по значению, поэтому функция получает копии этих целых и логических значений. Даже если функция изменяет их, копия вызывающего не затрагивается.
Так что я бы избегал лишних конст
источник
Я знаю, что этот вопрос "немного" устарел, но когда я натолкнулся на него, кто-то еще может сделать это в будущем ... ... все же я сомневаюсь, что бедняга будет здесь, чтобы прочитать мой комментарий :)
Мне кажется, что мы все еще слишком ограничены мышлением в стиле C. В парадигме ООП мы играем с объектами, а не с типами. Const-объект может концептуально отличаться от неконстантного объекта, в частности в смысле логического-const (в отличие от побитового-const). Таким образом, даже если постоянная корректность параметров функции является (возможно) чрезмерной осторожностью в случае POD, это не так в случае объектов. Если функция работает с const-объектом, она должна сказать об этом. Рассмотрим следующий фрагмент кода
PS: вы можете утверждать, что (const) ссылка будет более уместной здесь и дает вам такое же поведение. Ну правильно. Просто даю другую картину из того, что я мог видеть в другом месте ...
источник