Const правильность для параметров значения

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

// header
int func(int i);

// cpp
int func(const int i) {
    return i;
}

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

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

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

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

Исходя из этой рекомендации, также рекомендуется ли для значений указателя параметры указателя? (Это не имеет смысла для параметра ссылки, так как вы не можете переназначить ссылку.)

// header
int func1(int* i);
int func2(int* i);

// cpp
int func1(int* i) {
    int x = 0;

    *i = 3; // compiles without error
    i = &x; // compiles without error

    return *i;
}
int func2(int* const i) {
    int x = 0;

    *i = 3; // compiles without error
    i = &x; // compile error

    return *i;
}

Описание: Создание параметров-значений полезно для выявления некоторых логических ошибок. Это лучшая практика? Вы идете до крайности, оставляя const из файла заголовка? Это так же полезно, чтобы сопоставить значения указателя? Почему или почему нет?

Некоторые ссылки:

C++ const ключевое слово - использовать свободно? Использование const для параметров функции

Пример использования параметров const value:

bool are_ints_equal(const int i, const int j) {
    if (i = j) { // without the consts this would compile without error
        return true;
    } else {
        return false;
    }
    // return i = j; // I know it can be shortened
}

7 ответов

Решение

Мой взгляд на это:

Это неплохая идея, но проблема незначительна, и ваша энергия может быть лучше потрачена на другие вещи.

В своем вопросе вы привели хороший пример того, когда он может поймать ошибку, но иногда вы также в конечном итоге делаете что-то вроде этого:

void foo(const int count ...)
{
   int temp = count;  // can't modify count, so we need a copy of it
   ++temp;

   /* ... */
}

Плюсы и минусы незначительны в любом случае.

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

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

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

Например, я могу реализовать функцию C, которая принимает пару указателей на буфер - указатель на начало и указатель на конец. Я собираюсь поместить данные в буфер, но хочу убедиться, что я не пересекаю конец. Так что внутри функции есть код, который будет увеличивать указатель, когда я добавляю в него данные. Создание указателя на конец буфера const Параметр гарантирует, что я не буду кодировать ошибку, которая случайно увеличивает указатель конечной границы вместо указателя, который я действительно должен увеличивать.

Итак, функция fillArray с такой подписью:

size_t fillArray( data_t* pStart, data_t* const pEnd);

не позволит мне случайно увеличить pEnd когда я действительно хочу увеличить pStart, Это не так уж и много, но я уверен, что все, кто программировал на C в течение какого-то периода времени, сталкивались с такой ошибкой.

К сожалению, некоторые компиляторы (я смотрю на вас, Sun CC!) Неправильно различают аргументы, объявленные как const, и аргументы, не объявленные так, и вы можете получить ошибки о неопределенных функциях.

Я думаю, что это зависит от вашего личного стиля.

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

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

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

Если присутствует ключевое слово const; это означает, что значение 'i' (тип const) не может быть изменено. Если значение 'i' изменено внутри функции foo, компилятор выдаст ошибку: "

Не может изменить объект const

Но изменение "*i" (то есть *i = 3;) означает, что вы изменяете не значение "i", а значение адреса, на которое указывает "i"

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

Мы все время от времени должны распутывать чужой код C++. И этот чей-то код на C++ по определению является полным беспорядком:D.

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

Так что я действительно ценю, когда этот кто-то еще имеет const везде (включая значения параметров):D

Мне нравится постоянная корректность в таких ситуациях:
void foo(const Bar &b) //I know b cannot be changed
{
//do something with b
}

Это позволяет мне использовать b не боясь изменить его, но мне не нужно платить за конструктор копирования.

Другие вопросы по тегам