Использование const для параметров функции

Как далеко вы идете с 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)

Для этого есть причина? Это кажется немного необычным для меня.

30 ответов

Решение

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

I personally tend to not use const except for reference and pointer parameters. For copied objects it doesn't really matter, although it can be safer as it signals intent within the function. Это действительно суждение. I do tend to use const_iterator though when looping on something and I don't intend on modifying it, so I guess to each his own, as long as const correctness for reference types is rigorously maintained.

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

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

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

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

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

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

Ах, я бы хотел, чтобы переменные были константными по умолчанию, а переменные требовались для неконстантных переменных:)

Слишком много лишних констант плохо с точки зрения API:

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

Слишком много "const" в API, когда оно не нужно, похоже на " плачущего волка ", в конце концов, люди начнут игнорировать "const", потому что он повсюду и ничего не значит в большинстве случаев.

Аргумент "reductio ad absurdum" для дополнительных const в API хорош для этих первых двух пунктов: если больше параметров const хороши, то каждый аргумент, который может иметь const, ДОЛЖЕН иметь const на нем. На самом деле, если бы это было действительно так хорошо, вы бы хотели, чтобы const был параметром по умолчанию для параметров, а ключевое слово типа "изменяемый" имелось только тогда, когда вы хотите изменить параметр.

Итак, давайте попробуем положить в const, где мы можем:

void mungerum(char * buffer, const char * mask, int count);

void mungerum(char * const buffer, const char * const mask, const int count);

Рассмотрим строку кода выше. Не только объявление более загромождено, длиннее и труднее для чтения, но и пользователь API может безопасно игнорировать три из четырех ключевых слов "const". Тем не менее, дополнительное использование const сделало вторую строку потенциально ОПАСНОЙ!

Зачем?

Быстрое неверное прочтение первого параметра char * const buffer может заставить вас подумать, что он не изменит память в буфере данных, который передается, однако это не так! Избыточное "const" может привести к опасным и неверным предположениям о вашем API при сканировании или неправильном прочтении.


Лишние const также плохи с точки зрения реализации кода:

#if FLEXIBLE_IMPLEMENTATION
       #define SUPERFLUOUS_CONST
#else
       #define SUPERFLUOUS_CONST             const
#endif

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count);

Если FLEXIBLE_IMPLEMENTATION не соответствует действительности, то API "обещает" не реализовывать функцию первым способом ниже.

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       // Will break if !FLEXIBLE_IMPLEMENTATION
       while(count--)
       {
              *dest++=*source++;
       }
}

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       for(int i=0;i<count;i++)
       {
              dest[i]=source[i];
       }
}

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

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

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

inline void bytecopyWrapped(char * dest,
   const char *source, int count)
{
       while(count--)
       {
              *dest++=*source++;
       }
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source,SUPERFLUOUS_CONST int count)
{
    bytecopyWrapped(dest, source, count);
}

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

Эти лишние консты стоят не больше, чем обещание плохого парня из фильма.


Но способность лгать становится еще хуже

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

// Example of const only in definition, not declaration
class foo { void test(int *pi); };
void foo::test(int * const pi) { }

Тем не менее, обратное утверждение верно... вы можете поместить ложный констант только в объявлении и игнорировать его в определении. Это только делает лишнее const в API более ужасной вещью и ужасной ложью - см. Этот пример:

class foo
{
    void test(int * const pi);
};

void foo::test(int *pi) // Look, the const in the definition is so superfluous I can ignore it here
{
    pi++;  // I promised in my definition I wouldn't modify this
}

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

Посмотрите на этот пример. Что является более читабельным? Очевидно ли, что единственная причина появления дополнительной переменной во второй функции заключается в том, что какой-то разработчик API добавил лишнее const?

struct llist
{
    llist * next;
};

void walkllist(llist *plist)
{
    llist *pnext;
    while(plist)
    {
        pnext=plist->next;
        walk(plist);
        plist=pnext;    // This line wouldn't compile if plist was const
    }
}

void walkllist(llist * SUPERFLUOUS_CONST plist)
{
    llist * pnotconst=plist;
    llist *pnext;
    while(pnotconst)
    {
        pnext=pnotconst->next;
        walk(pnotconst);
        pnotconst=pnext;
    }
}

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

Следующие две строки функционально эквивалентны:

int foo (int a);
int foo (const int a);

Очевидно, вы не сможете изменить a в теле foo если это определено вторым способом, но нет никакой разницы со стороны.

куда const действительно пригодится с параметрами ссылки или указателя:

int foo (const BigStruct &a);
int foo (const BigStruct *a);

Это говорит о том, что foo может принимать большой параметр, возможно, структуру данных размером в гигабайты, не копируя его. Кроме того, он говорит вызывающему: "Foo не * изменит содержимое этого параметра". Передача константной ссылки также позволяет компилятору принимать определенные решения о производительности.

*: Если это не отбрасывает постоянство, но это другой пост.

const должен был быть по умолчанию в C++. Как это:

int i = 5 ; // i is a constant

var int i = 5 ; // i is a real variable

Когда я кодировал C++ для жизни, я использовал все, что мог. Использование const- отличный способ помочь компилятору помочь вам. Например, использование возвращаемых значений вашего метода может спасти вас от опечаток, таких как:

foo() = 42

когда вы имели в виду:

foo() == 42

Если функция foo() определена для возврата неконстантной ссылки:

int& foo() { /* ... */ }

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

const int& foo() { /* ... */ }

Устраняет эту возможность.

1. Лучший ответ, основанный на моей оценке:

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

2. Мои собственные слова (согласен с лучшим ответом):

  1. Для передачи по значению нет смысла добавлять const. Все, что он делает, это:
    1. ограничьте разработчика, который должен делать копию каждый раз, когда они хотят изменить входной параметр в исходном коде (это изменение в любом случае не будет иметь побочных эффектов, поскольку то, что передается, уже является копией, поскольку оно передается по значению). И часто для реализации функции используется изменение входного параметра, который передается по значению, поэтому добавлениеconst везде может этому помешать.
    2. и добавление const излишне загромождает код constповсюду, отвлекая внимание от consts, которые действительно необходимы для безопасного кода.
  2. При работе с указателями или ссылками, однако,constкритически важен, когда это необходимо, и должен использоваться, поскольку он предотвращает нежелательные побочные эффекты с постоянными изменениями вне функции, и поэтому каждый указатель или ссылка должны использоватьconstкогда параметр является только входом, а не выходом. С помощьюconst только для параметров, переданных по ссылке или указателю, дает дополнительное преимущество, делая действительно очевидным, какие параметры являются указателями или ссылками. Еще одна вещь - выделиться и сказать: "Осторожно! Любой параметр сconst рядом ссылка или указатель! ".
  3. То, что я описал выше, часто являлось консенсусом, достигнутым в профессиональных организациях по разработке программного обеспечения, в которых я работал, и считалось передовой практикой. Иногда даже правило было строгим: "никогда не используйте константу для параметров, которые передаются по значению, но всегда используйте ее для параметров, передаваемых по ссылке или указателю, если они являются только входами".

3. Слова Google (согласен со мной и лучший ответ):

(Из " Руководства по стилю Google C++ ")

Для параметра функции, переданного по значению, const не влияет на вызывающую программу, поэтому не рекомендуется в объявлениях функций. См. TotW # 109.

Использование const для локальных переменных не рекомендуется и не рекомендуется.

Источник: раздел "Использование константы" Руководства по стилю Google C++: https://google.github.io/styleguide/cppguide.html. На самом деле это действительно ценный раздел, поэтому прочтите весь раздел.

Обратите внимание, что "TotW #109" означает "Совет недели № 109: значимый.constв объявлениях функций ", и это также полезно для чтения. Это более информативное и менее предписывающее, что делать, и основанное на контексте, появилось до правила Google C++ Style Guide оconst цитируется чуть выше, но в результате предоставленной им ясности const Правило, указанное выше, было добавлено в Руководство по стилю Google C++.

Также обратите внимание, что хотя я цитирую Руководство по стилю Google C++ здесь в защиту своей позиции, это НЕ означает, что я всегда следую руководству или всегда рекомендую следовать руководству. Некоторые вещи, которые они рекомендуют, просто странные, например, ихkDaysInAWeek-стилевое соглашение об именах для "постоянных имен".Тем не менее, по-прежнему полезно и актуально указать, когда одна из самых успешных и влиятельных технических и программных компаний в мире использует то же оправдание, что и я, и другие, подобные @Adisak, для подтверждения нашей точки зрения по этому вопросу.

4. Линтер Clang, clang-tidy, есть несколько вариантов для этого:

A. Также стоит отметить, что линтер Clang, clang-tidy, есть опция, readability-avoid-const-params-in-decls, описанный здесь, для поддержки применения в кодовой базе, не использующейconstдля параметров функции передачи по значению:

Проверяет, имеет ли объявление функции параметры, которые являются константными параметрами верхнего уровня.

Значения const в объявлениях не влияют на сигнатуру функции, поэтому их не следует помещать туда.

Примеры:

void f(const string);   // Bad: const is top level.
void f(const string&);  // Good: const is not top level.

А вот еще два примера, которые я добавляю для полноты и ясности:

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

Б. Также есть такая возможность: readability-const-return-type- https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

5. Мой прагматичный подход к составлению руководства по стилю по этому вопросу:

Я бы просто скопировал и вставил это в свое руководство по стилю:

[КОПИРОВАНИЕ / ВСТАВИТЬ ЗАПУСК]

  1. Всегда используйте constна параметры функции, переданные по ссылке или указателю, когда их содержимое (то, на что они указывают) НЕ предназначено для изменения. Таким образом, становится очевидным, что переменная, переданная по ссылке или указателю, должна быть изменена, потому что в ней не будетconst. В этом случае использованияconst предотвращает случайные побочные эффекты вне функции.
  2. Это не рекомендуется для использованияconst на параметры функции, передаваемые по значению, потому что constне влияет на вызывающего: даже если переменная изменена в функции, не будет никаких побочных эффектов вне функции. См. Следующие ресурсы для дополнительного обоснования и понимания:
    1. "Руководство по стилю Google C++" Раздел "Использование константы"
    2. Совет недели № 109: значимый const в объявлениях функций "
    3. Ответ Adisak stackru на тему "Использование 'const' для параметров функции"
  3. " Никогда не используйте верхний уровеньconst [например: constпараметров, переданных по значению ] параметров функции в объявлениях, которые не являются определениями (и будьте осторожны, чтобы не копировать / вставлять бессмысленныеconst). Это бессмысленно и компилятор игнорирует это, это визуальный шум и может ввести читателей в заблуждение "( https://abseil.io/tips/109, выделено автором).
    1. Единственный const Квалификаторы, которые влияют на компиляцию, - это те, которые помещены в определение функции, а НЕ в предварительное объявление функции, например, в объявлении функции (метода) в файле заголовка.
  4. Никогда не используйте верхний уровеньconst [например: constдля переменных, передаваемых по значению ] для значений, возвращаемых функцией.
  5. С помощью constна указатели или ссылки, возвращаемые функцией, зависит от разработчика, так как это иногда бывает полезно.
  6. ЗАДАЧИ: выполните некоторые из вышеперечисленных с помощью следующих clang-tidy параметры:
    1. https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html
    2. https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

Вот несколько примеров кода, демонстрирующих const правила, описанные выше:

constПримеры параметров:
(некоторые заимствованы отсюда)

void f(const std::string);   // Bad: const is top level.
void f(const std::string&);  // Good: const is not top level.

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

constПримеры возвращаемых типов:
(некоторые заимствованы отсюда)

// BAD--do not do this:
const int foo();
const Clazz foo();
Clazz *const foo();

// OK--up to the implementer:
const int* foo();
const int& foo();
const Clazz* foo();

[КОНЕЦ КОПИРОВАНИЯ / ВСТАВКИ]

На эту тему есть хорошее обсуждение в старых статьях "Гуру недели" на comp.lang.C++., Модерируемых здесь.

Соответствующая статья GOTW доступна на веб-сайте Херба Саттера здесь.

Я использую const для параметров функции, которые являются ссылками (или указателями), которые являются только [in] данными и не будут изменены функцией. Это означает, что когда цель использования ссылки состоит в том, чтобы избежать копирования данных и не допустить изменения переданного параметра.

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

Подпись функции для

void foo(int a);

а также

void foo(const int a);

то же самое, что объясняет ваши.c и.h

Асаф

Я говорю const ваши значения параметров.

Рассмотрим эту глючную функцию:

bool isZero(int number)
{
  if (number = 0)  // whoops, should be number == 0
    return true;
  else
    return false;
}

Если бы числовым параметром был const, компилятор остановился бы и предупредил нас об ошибке.

Если вы используете ->* или же .* операторы, это обязательно.

Это мешает вам написать что-то вроде

void foo(Bar *p) { if (++p->*member > 0) { ... } }

что я почти сделал прямо сейчас, и который, вероятно, не делает то, что вы намерены.

То, что я хотел сказать, было

void foo(Bar *p) { if (++(p->*member) > 0) { ... } }

и если бы я положил const между Bar * а также pкомпилятор сказал бы мне это.

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

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

Наконец, функция, которая не изменяет текущий объект (this), может и, вероятно, должна быть объявлена ​​как const. Пример ниже:

int SomeClass::GetValue() const {return m_internalValue;}

Это обещание не изменять объект, к которому применяется этот вызов. Другими словами, вы можете позвонить:

const SomeClass* pSomeClass;
pSomeClass->GetValue();

Если функция не является константой, это приведет к предупреждению компилятора.

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

Маркировка значений параметров "const" - определенно субъективная вещь.

Однако я на самом деле предпочитаю отмечать значения параметров const, как в вашем примере.

void func(const int n, const long l) { /* ... */ }

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

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

Однако для более крупной функции это форма документации по реализации, и она обеспечивается компилятором.

Я могу быть уверен, что если я сделаю какое-то вычисление с 'n' и 'l', я смогу реорганизовать / переместить это вычисление, не боясь получить другой результат, потому что я пропустил место, где один или оба изменены.

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

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

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

Насколько я знаю, компилятор мог бы очень хорошо видеть параметр константного значения и сказать: "Эй, эта функция все равно не изменяет его, поэтому я могу перейти по ссылке и сохранить некоторые тактовые циклы". Я не думаю, что это когда-либо сделало бы такую ​​вещь, потому что это изменяет сигнатуру функции, но это имеет значение. Может быть, он выполняет какие-то другие манипуляции со стеком или что-то в этом роде. Дело в том, что я не знаю, но я знаю, что попытка быть умнее компилятора только приводит к тому, что мне стыдно.

В C++ есть дополнительный багаж с идеей правильности, поэтому он становится еще более важным.

Подвести итоги:

  • "Обычно const передача по значению не используется и в лучшем случае вводит в заблуждение". От GOTW006
  • Но вы можете добавить их в.cpp так же, как и в случае с переменными.
  • Обратите внимание, что стандартная библиотека не использует const. Например std::vector::at(size_type pos), То, что достаточно для стандартной библиотеки, хорошо для меня.

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

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

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

По оптимизации компилятора: http://www.gotw.ca/gotw/081.htm

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

Что действительно важно, так это пометить методы как const, если они не изменяют свой экземпляр. Делайте это по ходу дела, потому что в противном случае вы можете получить либо много const_cast<>, либо вы можете обнаружить, что маркировка метода const требует изменения большого количества кода, потому что он вызывает другие методы, которые должны были быть помечены как const.

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

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

Я не знал о разнице в объявлении файла.h /.cpp, но в этом есть какой-то смысл. На уровне машинного кода ничто не является "const", поэтому, если вы объявляете функцию (в.h) как неконстантную, код такой же, как если бы вы объявляли ее как const (без оптимизации). Тем не менее, это поможет вам подключить компилятор, чтобы вы не меняли значение переменной внутри реализации функции (.ccp). Это может пригодиться в том случае, если вы наследуете интерфейс, который позволяет вносить изменения, но вам не нужно менять параметр для достижения требуемой функциональности.

Я бы не стал использовать const для таких параметров - все уже знают, что логическое значение (в отличие от логического &) является константой, поэтому добавление его заставит людей думать: "Подожди, что?" или даже что вы передаете параметр по ссылке.

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

Используйте const, когда вы хотите, чтобы что-то не изменилось - это дополнительная подсказка, которая описывает, что делает ваша функция и чего ожидать. Я видел много C API, которые могли бы работать с некоторыми из них, особенно те, которые принимают c-строки!

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

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

Параметр Const полезен только тогда, когда параметр передается по ссылке, т. Е. По ссылке или по указателю. Когда компилятор видит параметр const, он проверяет, что переменная, используемая в параметре, не изменяется в теле функции. Почему кто-то хочет сделать параметр по значению как константу?:-)

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

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

Я знаю, что этот вопрос "немного" устарел, но, как только я наткнулся на него, кто-то еще может сделать это в будущем...... все же я сомневаюсь, что бедняга будет здесь, чтобы прочитать мой комментарий:)

Мне кажется, что мы все еще слишком ограничены мышлением в стиле C. В парадигме ООП мы играем с объектами, а не с типами. Const-объект может концептуально отличаться от неконстантного объекта, в частности в смысле логического-const (в отличие от побитового-const). Таким образом, даже если постоянная корректность параметров функции является (возможно) чрезмерной осторожностью в случае POD, это не так в случае объектов. Если функция работает с const-объектом, она должна сказать об этом. Рассмотрим следующий фрагмент кода

#include <iostream>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SharedBuffer {
private:

  int fakeData;

  int const & Get_(int i) const
  {

    std::cout << "Accessing buffer element" << std::endl;
    return fakeData;

  }

public:

  int & operator[](int i)
  {

    Unique();
    return const_cast<int &>(Get_(i));

  }

  int const & operator[](int i) const
  {

    return Get_(i);

  }

  void Unique()
  {

    std::cout << "Making buffer unique (expensive operation)" << std::endl;

  }

};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NonConstF(SharedBuffer x)
{

  x[0] = 1;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ConstF(const SharedBuffer x)
{

  int q = x[0];

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{

  SharedBuffer x;

  NonConstF(x);

  std::cout << std::endl;

  ConstF(x);

  return 0;

}

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

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

Так что я бы избегал лишних консерваторов, потому что

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