C ++ const ключевое слово - использовать свободно? - PullRequest
23 голосов
/ 12 октября 2009

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

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


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

Что лучше?

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

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

Ответы [ 12 ]

63 голосов
/ 12 октября 2009

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

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

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

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

Я не часто видел подобные вещи, и я тоже этим не занимаюсь. Наличие параметра 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 в этом значении следует использовать как можно чаще, поскольку это может помочь обеспечить правильность программы и улучшить самодокументирование кода.

42 голосов
/ 12 октября 2009

Рекомендую прочитать Херб Саттер. Исключительный C ++ . Есть глава "Const-Correctness".

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

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

void print(int number);

фактически такой же, как этот:

void print(int const number);

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

Читайте дальше, что рекомендует Херб Саттер:

"Избегайте передачи параметров const по значению в объявлениях функций. При этом оставьте параметр const в том же определении функции, если он не будет изменен."

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

void print(int const number);

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

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

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

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

23 голосов
/ 12 октября 2009

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

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

9 голосов
/ 12 октября 2009

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

8 голосов
/ 12 октября 2009

См. Meyers и 'Effective C ++' по этому вопросу, и действительно используйте const свободно, особенно с семантикой передачи по ссылке.

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

7 голосов
/ 12 октября 2009

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

Однако на более низком уровне модификатор 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 для значений параметров. Стоит оно того или нет - это другой вопрос ...

4 голосов
/ 12 ноября 2009

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


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

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

Некоторые компиляторы пренебрегают использованием потенциала оптимизации с использованием «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 / C ++. Если бы вы имели const, код даже не скомпилировался бы!

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


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

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

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

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

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

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

Вот ссылка: ответ .

4 голосов
/ 12 октября 2009

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

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;
}
4 голосов
/ 12 октября 2009

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

4 голосов
/ 12 октября 2009

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

...