Есть ли недостатки для обозначения всех переменных, которые вы не изменяете? - программирование
Подтвердить что ты не робот

Есть ли недостатки для обозначения всех переменных, которые вы не изменяете?

После долгих поисковых запросов я много узнал о функциях маркировки и их параметрах как const, но нет руководства по маркировке переменных как const.

Вот действительно простой пример:

#include <string>
#include <iostream>

void example(const std::string& x) {
  size_t length = x.length();
  for (size_t i = 0; i < length; ++i) {
    std::cout << x.at(i) << std::endl;
  }
}

int main() {
  example("hello");
}

Почему бы не сделать

size_t length = x.length();

const как

const size_t length = x.length();

по соглашению?

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

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

Есть ли недостаток, чтобы сделать это иначе, чем набрать дополнительные символы? Я не нашел много на эту тему, и я не хочу стрелять в ногу, если это проблема с таким количеством сотен.

4b9b3361

Ответ 1

Нет недостатков в маркировке переменных, которые вы не изменяете const.

Есть несколько сторонних сторон: компилятор поможет вам диагностировать, когда вы непреднамеренно изменяете переменную, которую вы не должны/не хотели, и компилятор может (хотя из-за языка с const_cast и mutable это редкость) генерировать лучший код.

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

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

Ответ 2

Я могу представить как минимум два недостатка:

  • verbosity: больше слов, больше символов для обработки,...
  • Инерция: если вам нужно ее изменить, вам нужно будет удалить и удалить этот const

и оба они того стоят.


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

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

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

Ответ 3

Вместо этого нестандартный код:

#import <string>
#import <iostream>

void example(const std::string& x) {
  size_t length = x.length();
  for (size_t i = 0; i < length; ++i) {
    std::cout << x.at(i) << std::endl;
  }
}

int main() {
  example("hello");
}

& hellip; Я бы написал следующее:

#include <string>
#include <iostream>
using namespace std;

void example( string const& s )
{
    for( char const ch : s )
    {
        cout << ch << '\n';
    }
}

auto main()
    -> int
{ example( "hello" ); }

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

Основной недостаток использования const для большинства вещей - это когда вы должны относиться к API C.

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


          Добавление 1:
Обратите внимание, что const для возвращаемого типа предотвращает семантику перемещения. Насколько я знаю, это было впервые отмечено Андреем Александреску в его статье Mojo (С++ 03 move semantics) в Dr Dobbs Journal:

" [A] const временный выглядит как оксюморон, противоречие в терминах. С практической точки зрения const временные силы принудительно копируют в пункте назначения.

Итак, это одно место, где нельзя использовать const.

Извините, что я забыл упомянуть об этом изначально; Мне был напомнен комментарий пользователя bogdan о другом ответе.


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

I.e., вместо

string stored_value;

void foo( string const& s )
{
    some_action( s );
    stored_value = s;
}

& hellip; или избыточность оптимизированных

string stored_value;

void foo( string const& s )
{
    some_action( s );
    stored_value = s;
}

void foo( string&& s )
{
    some_action( s );
    stored_value = move( s );
}

& hellip; рассмотрим только письмо

string stored_value;

void foo( string s )
{
    some_action( s );
    stored_value = move( s );
}

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


Примечания:
Стандарт С++ не имеет директивы #import. Кроме того, эти заголовки при правильном включении не гарантируют определение size_t в глобальном пространстве имен.

Ответ 4

Для локальной переменной size_t length в таком коротком методе это не имеет большого значения. Недостаток дополнительной многословности в основном балансирует с относительной безопасностью избегать опечаток, случайно изменяя длину. Сделайте что-нибудь свое руководство по местному стилю, или ваше собственное чувство кишки говорит вам.

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


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

Ответ 5

Я знаю, что такой маленький, простой пример действительно не показывает огромных Это полезно, но похоже, что это было бы полезно в более крупных codebase, где вы можете случайно изменить переменную, которую вы не должны мутировали.

Проблема в том, что это в принципе никогда не происходит.

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

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

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

Ответ 6

Я согласен с большинством ответов, данных до сих пор, с другой стороны, некоторые аспекты все еще отсутствуют.

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

Давайте еще раз взглянем на вопрос:

Есть ли недостатки для обозначения всех переменных, которые вы не изменяете? `

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

Вместо этого подумайте о самой переменной, спросите

  • Это полезно вообще?
  • Он также должен быть постоянным?

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

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

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

Поэтому не добавляйте const везде, где ваш компилятор разрешает это. Не соблазняйтесь "окаменять свой код"; -)