В основном это касается второй строки: лучшие практики, назначения, параметры функций и т. Д.
Общая практика. Попробуйте сделать все, что вы можете. Или, говоря иначе, сделайте все для начала const
, а затем удалите точно минимальный набор const
, необходимый для работы программы. Это будет большим подспорьем в достижении константности и поможет избежать появления незаметных ошибок, когда люди пытаются вводить вещи, которые они не должны изменять.
Избегайте const_cast <> как чума. Есть один или два законных варианта использования, но их очень мало и они далеко друг от друга. Если вы пытаетесь изменить объект const
, вам будет гораздо лучше найти того, кто объявил его const
в первом темпе, и обсудить с ними этот вопрос, чтобы достичь консенсуса относительно того, что должно произойти.
Что очень аккуратно приводит к выполнению заданий. Вы можете назначить что-то, только если это неконстантно. Если вы хотите присвоить что-то, что является постоянным, см. Выше. Помните, что в декларациях int const *foo;
и int * const bar;
разные вещи const
- другие ответы здесь освещают эту проблему превосходно, поэтому я не буду вдаваться в подробности.
Параметры функции:
Передача по значению: например, void func(int param)
Вас не волнует, так или иначе, на вызывающем сайте. Можно привести аргумент, что есть варианты использования для объявления функции как void func(int const param)
, но это не влияет на вызывающего, только на саму функцию, в том смысле, что любое переданное значение не может быть изменено функцией во время вызова.
Передать по ссылке: например, void func(int ¶m)
Теперь это имеет значение. Как только что объявлено, func
разрешено изменять param
, и любой вызывающий сайт должен быть готов справиться с последствиями. Изменение декларации на void func(int const ¶m)
изменяет контракт и гарантирует, что func
теперь не может изменить param
, что означает, что то, что передано, это то, что вернется. Как уже отмечали другие, это очень полезно для дешевой передачи большого объекта, который вы не хотите менять. Передача ссылки намного дешевле, чем передача большого объекта по значению.
Передача по указателю: например, void func(int *param)
и void func(int const *param)
Эти два в значительной степени синонимичны с их эталонными ссылками, с оговоркой, что вызываемой функции теперь нужно проверять на nullptr
, если какая-то другая договорная гарантия не гарантирует func
, что она никогда не получит nullptr
в param
.
Часть мнения на эту тему. Доказать правильность в таком случае адски сложно, просто чертовски легко ошибиться. Так что не рискуйте, и всегда проверяйте параметры указателя для nullptr
. Вы избавите себя от боли и страданий, и вам будет трудно найти ошибки в долгосрочной перспективе. А что касается стоимости проверки, то она очень дешевая, и в случаях, когда статический анализ, встроенный в компилятор, может управлять им, оптимизатор все равно ее исключит. Включите генерацию временного кода канала для MSVC или WOPR (я думаю) для GCC, и вы получите всю программу, то есть даже в вызовах функций, которые пересекают границу модуля исходного кода.
В конце концов, все вышеперечисленное дает веские основания всегда отдавать предпочтение ссылкам на указатели. Они просто безопаснее со всех сторон.