Почему мы используем const-массив в функции, даже исходный массив не const? [Дубликат]

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

obj.spam = 'eggs'
name = 'spam'
getattr(obj, name)  # returns 'eggs'

310
задан Michael Myers 5 May 2009 в 22:40
поделиться

28 ответов

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

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

146
ответ дан Krythic 22 August 2018 в 17:50
поделиться
  • 1
    Я не могу согласиться с частью «плохого стиля». Выброс const из прототипов функций имеет то преимущество, что вам не нужно изменять файл заголовка, если вы позже захотите отбросить const из части реализации. – Michał Górny 9 January 2010 в 12:53
  • 2
    «Я лично склонен не использовать const, кроме ссылочных и указательных параметров». Может быть, вам следует пояснить, что для «Я склонен не использовать излишние квалификаторы в объявлениях функций, но используйте const, где это делает полезную разницу. & Quot; – Deduplicator 9 September 2014 в 17:53
  • 3
    Я не согласен с этим ответом. Я наклоняю другой путь и отмечаю параметры const, когда это возможно; это более выразительно. Когда я читаю чужой код, я использую маленькие индикаторы, подобные этому, чтобы судить о том, как много внимания они уделяют написанию своего кода наряду с такими вещами, как магические числа, комментирование и правильное использование указателей и т. Д. – Ultimater 1 August 2016 в 20:27
  • 4
    int getDouble(int a){ ++a; return 2*a; } Попробуйте это. Конечно, ++a не имеет никакого отношения к этому, но он может быть найден там в длинной функции, написанной более чем одним программистом в течение длительного периода времени. Я настоятельно рекомендую написать int getDouble( const int a ){ //... }, который будет генерировать ошибку компиляции при поиске ++a;. – dom_beau 27 March 2017 в 03:58
  • 5

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

foo() = 42

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

foo() == 42

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

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

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

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

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

25
ответ дан 2 revs 22 August 2018 в 17:50
поделиться
  • 1
    С чем работал этот компилятор? GCC дает ошибку при попытке скомпилировать foo() = 42: ошибка: lvalue, требуемая как левый операнд присваивания – gavrie 9 February 2010 в 09:42
  • 2
    Это просто некорректно. foo () = 42 совпадает с 2 = 3, то есть ошибкой компилятора. И возвращение константы совершенно бессмысленно. Он не делает ничего для встроенного типа. – Josh 19 September 2011 в 05:14
  • 3
    Я столкнулся с этим использованием const, и я могу вам сказать, в конце концов, он создает больше проблем, чем преимуществ. Подсказка: const int foo() отличается от int foo(), что приводит к большим проблемам, если вы используете такие функции, как указатели на функции, системы сигналов / слотов или boost :: bind. – Mephane 23 September 2011 в 12:32
  • 4
    Да, вы действительно можете сделать foo() = 42. Код здесь: gist.github.com/1401793 – Avdi 28 November 2011 в 22:02
  • 5
    Я скорректировал код, чтобы включить возвращаемое значение ссылки. – Avdi 28 November 2011 в 22:05

Extra Superfluous const плохо работает с точки зрения API:

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

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

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

Так что давайте попробуем вставить мы можем:

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

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

Рассмотрим приведенную выше строку кода. Декларация не только более захламлена, но и длиннее и труднее читать, но три из четырех ключевых слов «const» могут быть безопасно проигнорированы пользователем API. Однако дополнительное использование «const» сделало вторую линию потенциально ОПАСНЫМ!

Почему?

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


Сверхбыстрая константа неэффективна и с точки зрения реализации кода:

#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 только в определение.

// 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
}

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

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

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;
    }
}

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

58
ответ дан Adisak 22 August 2018 в 17:50
поделиться
  • 1
    Почему вниз вниз? Это гораздо более полезно, если вы оставите короткий комментарий к нисходящей линии. – Adisak 23 February 2013 в 01:26
  • 2
    Весь смысл использования аргумента const заключается в том, чтобы сделать помеченную строку неудачной (plist = pnext). Это разумная мера безопасности, чтобы поддерживать функциональный аргумент неизменным. Я согласен с вашей точкой зрения, что они плохи в объявлениях функций (поскольку они суперплоские), но они могут служить их целям в блоке реализации. – touko 4 March 2013 в 22:49
  • 3
    @Adisak Я не вижу ничего плохого в вашем ответе, по сути, но из ваших комментариев кажется, что вам не хватает важного момента. Определение / реализация функции - это не часть API, которая является только функцией declaration . Как вы сказали, объявление функций с параметрами const бессмысленно и добавляет беспорядок. Однако пользователям API, возможно, никогда не понадобится его реализация. Между тем разработчик может решить, что const-qualify некоторые параметры в определении функции ТОЛЬКО для ясности, что совершенно нормально. – jw013 15 August 2013 в 20:17
  • 4
    @ jw013 является правильным, void foo(int) и void foo(const int) являются одной и той же функцией, а не перегрузками. ideone.com/npN4W4 ideone.com/tZav9R Здесь const является только деталью реализации тела функции и не влияет на разрешение перегрузки. Оставьте const из объявления, для более безопасного и опрятного API, но поместите const в определение , если вы не намерены изменять скопированное значение. – Oktalist 9 February 2014 в 02:07
  • 5
    @Adisak Я знаю, что это старо, но я считаю, что правильное использование публичного API было бы наоборот. Таким образом, разработчики, работающие над внутренними компонентами, не допускают ошибок, таких как pi++, когда они не должны. – CoffeeandCode 15 July 2014 в 05:28

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

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

121
ответ дан anatolyg 22 August 2018 в 17:50
поделиться
  • 1
    Const-antin ... Я вижу, что сделали твои родители – Terence 25 August 2015 в 21:03
  • 2
    «Я хочу, чтобы переменные были const по умолчанию». - оксиморон 8). Серьезно, как "consting" все помогает вам распутать код? Если исходный писатель изменил якобы постоянный аргумент, откуда вы знаете, что var должен был быть константой? Более того, подавляющее большинство переменных (без аргументов) предназначены для ... переменных. Итак, компилятор должен порвать очень скоро после того, как вы начали процесс, нет? – ysap 23 January 2017 в 08:59
  • 3
    @ysap, 1. Маркировка const как можно больше позволяет мне видеть, какие части движутся, а какие нет. По моему опыту, многие местные жители являются де-факто, а не наоборот. 2. «Константная переменная» / «Постоянная переменная» может звучать как оксюморон, но является стандартной практикой в ​​функциональных языках, а также некоторыми нефункциональными; см. Rust, например: doc.rust-lang.org/book/variable-bindings.html – Constantin 29 January 2017 в 17:49
  • 4
    Также стандартно теперь в некоторых случаях в c ++; например, лямбда [x](){return ++x;} является ошибкой; см. здесь – anatolyg 21 June 2017 в 14:08
  • 5
    Переменные "& quot; const" по умолчанию в Rust :) – phoenix 31 July 2017 в 12:46

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

Помещение константы в параметр boolean b в вашем примере только ограничивает реализацию и не делает,

Функциональная сигнатура для

void foo(int a);

и

void foo(const int a);

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

Asaf

7
ответ дан Asaf R 22 August 2018 в 17:50
поделиться

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

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

  • Они redudant
  • Они загромождают текст
  • Они предотвращают меня от изменения переданного значения в тех случаях, когда это может быть полезно или эффективно.
0
ответ дан AShelly 22 August 2018 в 17:50
поделиться

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

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

1
ответ дан Attila 22 August 2018 в 17:50
поделиться

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

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

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

2
ответ дан Aurélien Gâteau 22 August 2018 в 17:50
поделиться

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

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

Очевидно, вы не сможете изменить a в теле foo, если он определен вторым способом, но нет

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

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

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

*: Если это не исключает константу, но это еще одно сообщение.

69
ответ дан Ben Straub 22 August 2018 в 17:50
поделиться
  • 1
    Это не тот вопрос, о котором идет речь; конечно, для аргументов с привязкой или аргументами рекомендуется использовать const (если ссылочное или указанное значение не изменяется). Обратите внимание, что это не параметр , который является константой в примере вашего указателя; это то, на что указывает параметр. – tml 5 May 2016 в 09:12
  • 2
    & GT; Передача ссылки на константу также позволяет компилятору принимать определенные решения о производительности. классическая ошибка - компилятор должен определить для себя константу, ключевое слово const не помогает с этим благодаря сглаживанию указателей и const_cast – jheriko 4 October 2016 в 16:54

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

2
ответ дан bpeterson76 22 August 2018 в 17:50
поделиться

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

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

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

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

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

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

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

4
ответ дан Dan Hewett 22 August 2018 в 17:50
поделиться

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

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

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

0
ответ дан gbjbaanb 22 August 2018 в 17:50
поделиться
  • 1
    Я этого не понимаю. Почему вы были бы склонны опускать его в файле cpp (определение функции)? Вот где это на самом деле означает что-то и может ловить ошибки. Почему вы считаете, что лучше всего поставить const в обоих местах? В файле заголовка (объявление функции) это ничего не значит и загромождает API. Возможно, есть небольшое значение для того, чтобы decl и defn выглядели точно так же, но мне кажется, что это действительно незначительное преимущество по сравнению с проблемой загромождения API. – Don Hatch 13 October 2016 в 21:55
  • 2
    @DonHatch 8 лет спустя, ничего себе. Во всяком случае, как сказал OP, «я был также удивлен, узнав, что вы можете опустить const из параметров в объявлении функции, но можете включить его в определение функции». – gbjbaanb 14 October 2016 в 12:53

Возможно, это не будет правильным аргументом. но если мы увеличим значение переменной const внутри компилятора функции, мы получим ошибку: «error: increment of only-only parameter». так что это означает, что мы можем использовать ключевое слово const как способ предотвратить случайную модификацию наших переменных внутри функций (которые мы не должны использовать / только для чтения). поэтому, если мы случайно это сделали во время компиляции, компилятор сообщит об этом. это особенно важно, если вы не единственный, кто работает над этим проектом.

2
ответ дан HarshaXsoad 22 August 2018 в 17:50
поделиться

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

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

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

2
ответ дан jdmichal 22 August 2018 в 17:50
поделиться

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

0
ответ дан Khoth 22 August 2018 в 17:50
поделиться
  • 1
    иногда вам нужно передать объект по ссылке (по соображениям производительности), но не изменять его, поэтому const обязательно. Сохранение всех таких параметров - даже bools - const будет хорошей практикой, что упростит чтение кода. – gbjbaanb 22 September 2008 в 21:19

Параметры значения маркировки «const» определенно являются субъективными.

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

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

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

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

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

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

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

4
ответ дан Lloyd 22 August 2018 в 17:50
поделиться

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

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

2
ответ дан Luke Halliwell 22 August 2018 в 17:50
поделиться

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

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

0
ответ дан MarkR 22 August 2018 в 17:50
поделиться

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

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

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

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

То, что я собирался сказать, было

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

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

7
ответ дан Mehrdad 22 August 2018 в 17:50
поделиться
  • 1
    Я сразу же буду проверять ссылку на приоритет оператора, когда я собираюсь объединить это множество операторов (если я еще не знаю 100%), поэтому ИМО это не проблема. – mk12 26 August 2012 в 03:15

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

5
ответ дан Nemanja Trifunovic 22 August 2018 в 17:50
поделиться

Будучи программистом VB.NET, которому необходимо использовать программу на C ++ с 50+ открытыми функциями и файл .h, который спорадически использует спецификатор const, трудно узнать, когда обращаться к переменной с помощью ByRef или ByVal.

Конечно, программа сообщает вам, генерируя ошибку исключения на строке, где вы допустили ошибку, но тогда вам нужно угадать, какой из 2-10 параметров неверен.

So теперь у меня есть неприятная задача попытаться убедить разработчика, что они должны действительно определять свои переменные (в файле .h) таким образом, который позволяет автоматически автоматизировать метод создания всех определений функций VB.NET. Затем они самодовольно скажут: «прочитайте ... документацию».

Я написал awk-скрипт, который анализирует файл .h и создает все команды Declare Function, но без указателя относительно того, какие переменные являются R / O vs R / W, он делает только половину задание.

EDIT:

При поощрении другого пользователя я добавляю следующее:

Вот пример плохо сформированного (IMO). h entry;

typedef int (EE_STDCALL *Do_SomethingPtr)( int smfID, const char* cursor_name, const char* sql );

Результат VB из моего скрипта;

    Declare Function Do_Something Lib "SomeOther.DLL" (ByRef smfID As Integer, ByVal cursor_name As String, ByVal sql As String) As Integer

Обратите внимание на отсутствующую «const» в первом параметре. Без него программа (или другой разработчик) не имеет идеи, первый параметр должен быть передан «ByVal». Добавляя «const», он делает сам файл .h, так что разработчики, использующие другие языки, могут легко писать рабочий код.

-1
ответ дан Paul Stearns 22 August 2018 в 17:50
поделиться
  • 1
    @anatolyg, вы правы, это напыщенная речь, но она идентифицирует проблему с неправильным использованием понятий на языке, который может не потребоваться, но обеспечивает удобство использования и самостоятельную документацию. Если вы пишете код, который требует использования другими разработчиками, важно сделать его пригодным для использования. Если кто-то найдет это полезным, я был бы рад опубликовать сценарий AWK, но он работает только в том случае, если файл .h хорошо сформирован. – Paul Stearns 28 May 2017 в 19:50
  • 2
    Чтобы проиллюстрировать вашу точку зрения, вам лучше разместить плохой пример *.h и хороший. А также переведенный файл и показать, где сценарий имел проблемы, и как проблемы исчезают, если вы используете const в нужном месте. – anatolyg 29 May 2017 в 08:21
  • 3
    @anatolyg, это лучше? – Paul Stearns 29 May 2017 в 11:45
  • 4
    По крайней мере, сейчас я понимаю, что вы пытаетесь сказать! Но я не согласен: оба int smfID и const int smfID означают «передавать по значению», в C ++, тогда как int& smfID означает «передать по ссылке». – anatolyg 29 May 2017 в 13:42
  • 5
    @anatolyg. .h-файл не имеет & quot; & amp; & quot; в нем, и эти параметры, по-видимому, используются взаимозаменяемо для ByRef / ByVal. Единственный способ, который я обнаружил, - либо выполнить поиск в документации файла .CHM, либо дождаться, пока моя программа взорвется с «System.AccessViolationException», и попытаться выяснить, какой параметр он есть. Специфическая dll, которую я использую в настоящее время, имеет ~ 100 общедоступных методов, и я хотел бы автоматизировать создание «Объявлять функции». – Paul Stearns 29 May 2017 в 14:45

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

Мне кажется, что мы все еще слишком ограничены способом мышления в стиле С. В парадигме ООП мы играем с объектами, а не с типами. Объект Const может быть концептуально отличным от неконстантного объекта, в частности, в смысле логического-const (в отличие от bitwise-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) здесь будет более уместной и даст вам такое же поведение. Ну, ладно. Просто давая другую картину из того, что я мог видеть в другом месте ...

0
ответ дан PavDub 22 August 2018 в 17:50
поделиться

const должен был быть значением по умолчанию в C ++. Например:

int i = 5 ; // i is a constant

var int i = 5 ; // i is a real variable
34
ответ дан QBziZ 22 August 2018 в 17:50
поделиться
  • 1
    Именно мои мысли. – Constantin 22 October 2008 в 09:43
  • 2
    Совместимость с C слишком важна, по крайней мере, для людей, которые проектируют C ++, даже для этого. – user 16 March 2010 в 05:57
  • 3
    Интересно, я никогда об этом не думал. – Dan 18 September 2012 в 21:56
  • 4
    Аналогично, unsigned должен был быть значением по умолчанию в C ++. Например: int i = 5; // i is unsigned и signed int i = 5; // i is signed. – hkBattousai 21 July 2015 в 13:49

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

Неверно.

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

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

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

344
ответ дан rlerallut 22 August 2018 в 17:50
поделиться
  • 1
    Полностью согласен. Все дело в общении с людьми и ограничении того, что можно сделать с переменной, что нужно сделать. – Len Holgate 22 September 2008 в 22:08
  • 2
    Я проголосовал за это. Я думаю, что вы разбавляете то, что вы пытаетесь указать с помощью const, когда вы применяете его к простым аргументам pass through. – tonylo 23 September 2008 в 09:02
  • 3
    Я проголосовал за это. Объявление параметра 'const' добавляет семантическую информацию к параметру. Они подчеркивают, что предполагал первоначальный автор кода, и это будет способствовать поддержанию кода с течением времени. – Richard Corden 23 September 2008 в 09:20
  • 4
    @tonylo: вы неправильно поняли. Речь идет о маркировке локальной переменной как const внутри блока кода (что является функцией). Я бы сделал то же самое для любой локальной переменной. Он ортогонален наличию API, который является const-правильным, что также важно. – rlerallut 23 September 2008 в 09:50
  • 5
    И он может ловить ошибки внутри функции - если вы знаете, что параметр не должен быть изменен, тогда объявление его const означает, что компилятор скажет вам, если вы его случайно измените. – Adrian 1 October 2008 в 02:03

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

1
ответ дан sdcvvc 22 August 2018 в 17:50
поделиться

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

0
ответ дан user 22 August 2018 в 17:50
поделиться

Хорошая дискуссия по этой теме в старых статьях «Гуру недели» на comp.lang.c ++. moderated здесь .

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

13
ответ дан Void 22 August 2018 в 17:50
поделиться
  • 1
    Herb Sutter - действительно умный парень :-) Определенно стоит прочитать, и я согласен со всеми его точками. – Adisak 14 June 2012 в 16:59
  • 2
    Хорошая статья, но я не согласен с ним в отношении аргументов. Я также делаю их const, потому что они похожи на переменные, и я никогда не хочу, чтобы кто-либо вносил какие-либо изменения в мои аргументы. – QBziZ 3 July 2012 в 13:31

Подводя итог:

  • «Обычно константа const-by-value является нецелесообразной и в лучшем случае вводит в заблуждение». Из GOTW006
  • Но вы можете добавить их в .cpp так же, как и с переменными.
  • Обратите внимание, что стандартная библиотека не использует const. Например. std::vector::at(size_type pos). Что хорошего для стандартной библиотеки, хорошо для меня.
1
ответ дан YvesgereY 22 August 2018 в 17:50
поделиться
  • 1
    «Что хорошо для стандартной библиотеки, хорошо для меня». не всегда верно. Например, стандартная библиотека использует уродские имена переменных, такие как _Tmp все время - вы не хотите этого (на самом деле вам не разрешено использовать их). – anatolyg 27 July 2017 в 07:44
  • 2
    @anatolyg - это деталь реализации – Fernando Pelliccioni 20 September 2017 в 16:41
  • 3
    ОК, как имена переменных, так и const-квалифицированные типы в списках аргументов являются деталями реализации. Я хочу сказать, что реализация стандартной библиотеки иногда не очень хороша. Иногда вы можете (и должны) делать лучше. Когда был написан код стандартной библиотеки - 10 лет назад? 5 лет назад (некоторые новейшие его части)? Сегодня мы можем написать лучший код. – anatolyg 23 September 2017 в 12:47
Другие вопросы по тегам:

Похожие вопросы: