Ключевое слово С++ const - использовать либерально?

В следующих функциях С++:

void MyFunction(int age, House &purchased_house)
{
    ...
}


void MyFunction(const int age, House &purchased_house)
{
    ...
}

Что лучше?

В обоих случаях "возраст" передается по значению. Мне интересно, нужно ли ключевое слово 'const': оно кажется излишним для меня, но также полезно (в качестве дополнительного указания переменная не будет меняться).

Есть ли у кого-нибудь мнение относительно того, какие из них (если таковые имеются) выше?

Ответ 1

Это, ИМХО, злоупотребляет. Когда вы говорите "const int age...", то, что вы на самом деле говорите, "вы не можете изменить даже локальную копию внутри вашей функции". То, что вы делаете, на самом деле делает код программиста менее удобочитаемым, заставляя его использовать другую локальную копию, когда он хочет изменить возраст/передать его неконстантной ссылкой.

Любой программист должен быть знаком с разницей между передачей по ссылке и переходом по значению так же, как любой программист должен понимать "const".

Ответ 2

Во-первых, это просто деталь реализации, и если вы помещаете const там, не помещайте ее в набор объявлений (заголовок). Поместите его только в файл реализации:

// header
void MyFunction(int age, House &purchased_house);

// .cpp file
void MyFunction(const int age, House &purchased_house);
{
    ...
}

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

Я часто этого не видел, и я тоже этого не делаю. Наличие параметра const будет запутывать меня чаще, чем помощь, потому что я сразу же сопоставляю шаблону и отказываюсь от него "const int & age":) Конечно, дело полностью отличается от const на другом уровне:

// const is a *good* thing here, and should not be removed,
// and it is part of the interface
void MyFunction(const string &name, House &purchased_house);
{
    ...
}

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

Ответ 3

Я рекомендую читать Herb Sutter. Исключительный С++. Существует глава "Const-Correctness".

"На самом деле, для компилятора, сигнатура функции одинакова, включаете ли вы эту константу перед параметром значения или нет".

Это означает, что эта подпись

void print(int number);

является тем же самым:

void print(int const number);

Итак, компилятору нет никакой разницы, как вы объявляете функцию. И вы не можете перегрузить его, поставив ключевое слово const перед параметром pass by value.

Далее, что рекомендует Herb Sutter:

"Избегайте параметров const-by-value const в объявлениях функций. Все-таки сделайте параметр const в том же определении функции, если он не будет изменен".

Он рекомендует избегать:

void print(int const number);

Потому что эта константа путаница, многословная и избыточная.

Но в определении вы должны делать это (если вы не измените параметр):

void print(int const number)
{
   // I don't want to change the number accidentally here
   ...
}

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

Ответ 4

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

Ответ 5

См. Meyers и "Эффективный С++" на этом, и используйте const свободно, особенно с семантикой pass-by-reference.

В этом случае атомных переменных эффективность не имеет значения, но ясность кода все же приносит пользу.

Ответ 6

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

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

int foo(const int a, const double b, const long c) {
   /* whatever */
}

void bar(const int a, const double b, const long c) {
   /* whatever */
}

Скажем где-то в коде, который они называются следующим образом

foo(x, d, m);
bar(x, d, m);

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

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

Неверно сказать, что это "бесполезно" или "не имеет никакого эффекта", хотя с типичным компилятором это может быть так.

Еще одно соображение, которое стоит упомянуть, носит разный характер. Существуют стандарты кодирования, которые требуют, чтобы кодеры не меняли начальные значения параметров, так как в "не использовать параметры как обычные локальные переменные значения параметров должны оставаться неизменными во всей функции". Этот вид имеет смысл, поскольку иногда он упрощает определение значений параметров, которые первоначально были заданы функцией (в то время как в отладчике, внутри тела функции). Чтобы обеспечить соблюдение этого стандарта кодирования, люди могут использовать спецификаторы const для значений параметров. Стоит ли это того или нет, это другой вопрос...

Ответ 7

Вы правы, единственная цель "const int age" заключается в том, что возраст не может быть изменен. Это может быть очень запутанным для большинства программистов. Поэтому, если этот подход не используется широко в вашем коде, я бы советовал опустить const.

Ответ 8

Вы должны использовать const для параметра if (и только если), вы использовали бы его для любой другой локальной переменной, которая не будет изменена:

const int age_last_year = age - YEAR;

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

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

Итак, либо:

void MyFunction(const int age, House &purchased_house)
{
    const int age_last_year = age - YEAR;
}

или

void MyFunction(int age, House &purchased_house)
{
    int age_last_year = age - YEAR;
}

Ответ 9

Одним из преимуществ использования const является то, что вы не можете случайно изменить значение age в середине MyFunction (в случае, если вы забыли, что он не прошел по ссылке). Один "недостаток" заключается в том, что вы не можете перерабатывать age с кодом типа foo.process(++age);.

Ответ 10

Второй вариант лучше. В первом случае вы можете случайно изменить переменный возраст.

Ответ 11

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

С другой стороны, rreferences и нетривиальные типы объектов должны всегда использовать const, если не будут внесены какие-либо изменения в объект. Теоретически это может позволить некоторую оптимизацию, но большая победа - это контракт, о котором я упоминал выше. Недостатком, конечно же, является то, что он может сделать ваш интерфейс намного крупнее, и трудно переопределить его в существующую систему (или с помощью стороннего API, не использующего const везде).

Ответ 12

Вот несколько замечательных статей и книга, которую я нашел, объясняя преимущества использования const:


Могу ли я предложить вам следующую схему?

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

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


Для тех, кто, похоже, не понимает полезность константы в параметре по значению функции/метода... вот краткий пример, объясняющий, почему:

.cpp

void WriteSequence(int const *, const int);

int main()
{
    int Array[] = { 2, 3, 4, 10, 12 };
    WriteSequence(Array, 5);
}


#include <iostream>
using std::cout;
using std::endl;
void WriteSequence(int const *Array, const int MAX)
{
    for (int const * i = Array; i != Array + MAX; ++i)
      cout << *i << endl;
}

Что бы произошло, если бы я удалил const перед int MAX, и я написал MAX + 1 внутри, как это?

void WriteSequence(int Array[], int MAX)
{
    MAX += MAX;
    for (int * i = Array; i != Array + MAX; ++i)
      cout << *i << endl;
}

Хорошо, ваша программа потерпит крах! Теперь зачем кому-то писать "MAX + = MAX;"? Возможно, человеческая ошибка, может быть, программист плохо себя чувствовал в тот день, или, может быть, программист просто не знал, как писать код на C/С++. Если бы у вас был const, код даже не был бы скомпилирован!

Безопасный код - это хороший код, и он не стоит ничего добавить "const" , когда он у вас есть!


Вот ответ из другого поста для очень похожего вопроса:

"const бессмысленно, когда аргумент передается по значению, так как вы не будете изменять объект вызывающего абонента."

Неправильно.

Это о самодокументировании вашего кода и ваши предположения.

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

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

Вот ссылка: answer.