Используйте функцию встроенного getattr
, чтобы получить атрибут объекта по имени. Измените имя по мере необходимости.
obj.spam = 'eggs'
name = 'spam'
getattr(obj, name) # returns 'eggs'
Причина в том, что const для параметра применяется только локально внутри функции, поскольку он работает с копией данных. Это означает, что сигнатура функции действительно одинакова. Это, вероятно, плохой стиль, чтобы сделать это много.
Я лично склонен не использовать const, кроме параметров ссылки и указателя. Для скопированных объектов это не имеет особого значения, хотя это может быть более безопасным, поскольку оно сигнализирует о намерении внутри функции. Это действительно вызов. Я, как правило, использую const_iterator, хотя, когда зацикливаюсь на чем-то, и я не намерен его модифицировать, поэтому я предполагаю, что каждый из них сам по себе, если строго соблюдается корректность для ссылочных типов.
Когда я кодировал C ++ для жизни, я составлял все, что мог. Использование const - отличный способ помочь компилятору помочь вам. Например, константа возвращаемых значений метода может спасти вас от опечаток, таких как:
foo() = 42
, когда вы имели в виду:
foo() == 42
Если foo () определен для возврата ссылка не const:
int& foo() { /* ... */ }
Компилятор с радостью позволит вам назначить значение анонимному времени, возвращаемому вызовом функции. Создание константы:
const int& foo() { /* ... */ }
Устраняет эту возможность.
foo() = 42
: ошибка: lvalue, требуемая как левый операнд присваивания
– gavrie
9 February 2010 в 09:42
const int foo()
отличается от int foo()
, что приводит к большим проблемам, если вы используете такие функции, как указатели на функции, системы сигналов / слотов или boost :: bind.
– Mephane
23 September 2011 в 12:32
foo() = 42
. Код здесь: gist.github.com/1401793
– Avdi
28 November 2011 в 22:02
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, раздражающая наг, мелкое и бессмысленное обещание, ненужное препятствие и иногда приводит к очень опасным ошибкам.
void foo(int)
и void foo(const int)
являются одной и той же функцией, а не перегрузками. ideone.com/npN4W4 ideone.com/tZav9R Здесь const является только деталью реализации тела функции и не влияет на разрешение перегрузки. Оставьте const из объявления, для более безопасного и опрятного API, но поместите const в определение i>, если вы не намерены изменять скопированное значение.
– Oktalist
9 February 2014 в 02:07
pi++
, когда они не должны.
– CoffeeandCode
15 July 2014 в 05:28
Иногда (слишком часто!) Я должен распутать чужой код на C ++. И все мы знаем, что чей-то код C ++ является полным беспорядком почти по определению :) Итак, первое, что я делаю, чтобы расшифровать локальный поток данных, ставится const в каждом определении переменной до тех пор, пока компилятор не начнет лаять. Это также означает аргументы const-qualifying value, потому что это просто причудливые локальные переменные, инициализированные вызывающим.
Ах, я бы хотел, чтобы переменные были const по умолчанию, а переменная была необходима для неконстантных переменных:)
[x](){return ++x;}
является ошибкой; см. здесь
– anatolyg
21 June 2017 в 14:08
Я использую const для параметров функции, которые являются ссылками (или указателями), которые являются только [in] данными и не будут изменены функцией. Значение, когда цель использования ссылки заключается в том, чтобы избежать копирования данных и не допускать изменения переданного параметра.
Помещение константы в параметр boolean b в вашем примере только ограничивает реализацию и не делает,
Функциональная сигнатура для
void foo(int a);
и
void foo(const int a);
- это функция, которая может использоваться для интерфейса класса (хотя обычно не рекомендуется изменять параметры). то же, что объясняет ваши .c и .h
Asaf
Все константы в ваших примерах не имеют никакой цели. По умолчанию C ++ по умолчанию передается по значению, поэтому функция получает копии этих int и boolean. Даже если функция действительно их модифицирует, копия вызывающего абонента не изменяется.
Таким образом, я бы избегал дополнительных констант, потому что
Если параметр передается по значению (и не является ссылкой), обычно нет большой разницы, объявлен ли параметр как const или нет (если он не содержит ссылочный элемент - не проблема для встроенных типов ). Если параметр является ссылкой или указателем, обычно лучше защищать ссылочную / направленную память, а не сам указатель (я думаю, вы не можете сделать ссылку самой const, а не то, что она имеет большое значение, поскольку вы не можете изменить рефери) , Кажется хорошей идеей защищать все, что вы можете, как const. Вы можете опустить его, не опасаясь совершить ошибку, если параметры являются просто POD (включая встроенные типы), и нет никаких шансов, что они будут меняться дальше по дороге (например, в вашем примере параметр bool).
Я не знал о различиях описания файла .h / .cpp, но это имеет смысл. На уровне машинного кода ничто не является «const», поэтому, если вы объявите функцию (в .h) как неконстантную, код будет таким же, как если бы вы объявили его как const (оптимизация в сторону). Тем не менее, это поможет вам заручиться компилятором, что вы не измените значение переменной внутри реализации функции (.ccp). Это может пригодиться в случае, когда вы наследуете интерфейс, который позволяет изменять, но вам не нужно изменять параметр для достижения требуемой функциональности.
Я не использую const для параметрируемых значений. Вызывающему не важно, изменяете ли вы параметр или нет, это детализация реализации.
Что действительно важно, это отметить методы как const, если они не изменяют свой экземпляр. Сделайте это, когда вы идете, потому что иначе вы могли бы получить либо много const_cast & lt;> или вы могли бы обнаружить, что маркировка метода const требует изменения большого количества кода, потому что он вызывает другие методы, которые должны были быть отмечены как const.
Я также склонен отмечать локальные константы, если мне не нужно их модифицировать. Я считаю, что это облегчает понимание кода, упрощая идентификацию «движущихся частей».
Следующие две строки функционально эквивалентны:
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, если смогу. Константа для параметров означает, что они не должны изменять свое значение. Это особенно важно при передаче по ссылке. const для функции объявляет, что функция не должна изменять члены классов.
const бесполезно, когда аргумент передается по значению, поскольку вы не будете изменять объект вызывающего объекта.
const должен быть предпочтительным при передаче по ссылке, если целью функции не является изменение переданного значение.
Наконец, функция, которая не изменяет текущий объект (это), может и, вероятно, должна быть объявлена const. Ниже приведен пример:
int SomeClass::GetValue() const {return m_internalValue;}
Это обещание не изменять объект, к которому применяется этот вызов. Другими словами, вы можете вызвать:
const SomeClass* pSomeClass;
pSomeClass->GetValue();
Если функция не была const, это приведет к предупреждению компилятора.
вещь, которую нужно запомнить с помощью const, заключается в том, что с самого начала гораздо проще делать вещи const, чем пытаться их поместить позже.
Использовать const, когда вы хотите, чтобы что-то не изменилось - его дополнительный намек, который описывает, что делает ваша функция и что ожидать. Я видел много API C, которые могли бы сделать с некоторыми из них, особенно с теми, которые принимают c-строки!
Я был бы более склонным опускать ключевое слово const в файле cpp, чем заголовок, но, поскольку я склоняюсь к тому, чтобы вырезать + вставить их, они будут храниться в обоих местах. Я понятия не имею, почему компилятор допускает это, я думаю, что это компилятор. Лучшая практика - это установить ключевое слово const в обоих файлах.
Возможно, это не будет правильным аргументом. но если мы увеличим значение переменной const внутри компилятора функции, мы получим ошибку: «error: increment of only-only parameter». так что это означает, что мы можем использовать ключевое слово const как способ предотвратить случайную модификацию наших переменных внутри функций (которые мы не должны использовать / только для чтения). поэтому, если мы случайно это сделали во время компиляции, компилятор сообщит об этом. это особенно важно, если вы не единственный, кто работает над этим проектом.
Я стараюсь использовать const везде, где это возможно. (Или другое подходящее ключевое слово для целевого языка.) Я делаю это исключительно потому, что он позволяет компилятору делать дополнительные оптимизации, которые он не сможет сделать иначе. Поскольку я понятия не имею, что такое оптимизация, я всегда это делаю, даже там, где это кажется глупым.
Насколько мне известно, компилятор может очень хорошо увидеть параметр const value и сказать: «Эй , эта функция в любом случае не модифицирует его, поэтому я могу пройти по ссылке и сохранить некоторые тактовые циклы ». Я не думаю, что когда-нибудь это будет сделано, так как это изменяет подпись функции, но в этом есть смысл. Может быть, он делает несколько манипуляций с стеком или что-то в этом роде ... Дело в том, что я не знаю, но я знаю, что пытаюсь быть умнее, чем компилятор только приводит к тому, что мне стыдно.
У C ++ есть некоторые дополнительный багаж, с идеей const-correctness, поэтому он становится еще более важным.
Я бы не поставил const на такие параметры - все уже знают, что логическое (в отличие от логического & amp;) постоянное, поэтому добавление его заставит людей подумать «подождите, что?» или даже что вы передаете параметр по ссылке.
Параметры значения маркировки «const» определенно являются субъективными.
Однако я фактически предпочитаю отмечать значения параметров const, как и в вашем примере.
void func(const int n, const long l) { /* ... */ }
Значение для меня ясно указано, что значения параметров функции никогда не изменяются функцией. Они будут иметь такое же значение в начале, как и в конце. Для меня это часть стиля очень функционального программирования.
Для короткой функции это, возможно, пустая трата времени / пространства, чтобы иметь «const», поскольку она обычно довольно очевидна что аргументы не изменяются функцией.
Однако для большей функции это форма документации по реализации, и она выполняется компилятором.
Я могу быть уверен если я сделаю некоторые вычисления с помощью «n» и «l», я могу реорганизовать / переместить это вычисление, не опасаясь получить другой результат, потому что я пропустил место, где один или оба были изменены.
Поскольку это детали реализации, вам не нужно объявлять значения параметров const в заголовке, так же, как вам не нужно объявлять параметры функции с теми же именами, что и реализация.
В случае, если вы упомянули, это не влияет на вызывающих абонентов вашего API, поэтому он обычно не делается (и не нужен в заголовке). Это влияет только на реализацию вашей функции.
Это не так уж плохо, но преимущества не так уж хороши, учитывая, что это не влияет на ваш API, и это добавляет ввод текста, так что это обычно не делал.
Нет причин для создания параметра значения «const», поскольку функция может в любом случае модифицировать копию переменной.
Причиной использования «const» является то, что вы передаете что-то более крупный (например, структура с множеством членов) по ссылке, и в этом случае он гарантирует, что функция не может его изменить; или, скорее, компилятор будет жаловаться, если вы попытаетесь изменить его обычным способом. Это предотвращает случайное изменение.
->*
или .*
, это обязательно. Это мешает вам написать что-то вроде
void foo(Bar *p) { if (++p->*member > 0) { ... } }
, которое я почти сделал прямо сейчас , и который, вероятно, не делает того, что вы намереваетесь.
То, что я собирался сказать, было
void foo(Bar *p) { if (++(p->*member) > 0) { ... } }
, и если бы я поставил const
между Bar *
и p
, компилятор сказал бы мне это.
Ах, жесткий. С одной стороны, декларация является контрактом, и на самом деле не имеет смысла передавать аргумент const по значению. С другой стороны, если вы посмотрите на реализацию функции, вы даете компилятору больше шансов на оптимизацию, если вы объявите константу аргумента.
Будучи программистом 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, так что разработчики, использующие другие языки, могут легко писать рабочий код.
*.h
и хороший. А также переведенный файл и показать, где сценарий имел проблемы, и как проблемы исчезают, если вы используете const
в нужном месте.
– anatolyg
29 May 2017 в 08:21
int smfID
и const int smfID
означают «передавать по значению», в C ++, тогда как int& smfID
означает «передать по ссылке».
– anatolyg
29 May 2017 в 13:42
Я знаю, что вопрос «немного» устарел, но по мере того, как я натолкнулся на него, кто-то еще может это сделать и в будущем ... ... все же я сомневаюсь, что бедный парень перечислит здесь, чтобы прочитать мой комментарий:)
Мне кажется, что мы все еще слишком ограничены способом мышления в стиле С. В парадигме ООП мы играем с объектами, а не с типами. Объект 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) здесь будет более уместной и даст вам такое же поведение. Ну, ладно. Просто давая другую картину из того, что я мог видеть в другом месте ...
const должен был быть значением по умолчанию в C ++. Например:
int i = 5 ; // i is a constant
var int i = 5 ; // i is a real variable
unsigned
должен был быть значением по умолчанию в C ++. Например: int i = 5; // i is unsigned
и signed int i = 5; // i is signed
.
– hkBattousai
21 July 2015 в 13:49
«const бессмысленно, когда аргумент передается по значению, так как вы не будете изменять объект вызывающего».
Неверно.
Это о самодокументировании вашего кода и ваших предположений.
Если ваш код содержит много людей, работающих над ним, а ваши функции нетривиальны, тогда вы должны пометить «const» any и все, что вы можете. Когда вы пишете код промышленной силы, вы всегда должны полагать, что ваши коллеги - психопаты, пытающиеся получить вас любым способом (особенно потому, что это часто происходит в будущем).
Кроме того, как упоминалось ранее, может помочь компилятору немного оптимизировать вещи (хотя это длинный снимок).
О оптимизации компилятора: http://www.gotw.ca/gotw/081.htm
Поскольку параметры передаются по значению, это не имеет никакого значения, если вы укажете const или нет с точки зрения вызывающей функции. В принципе не имеет смысла объявлять параметры pass по значению как const.
Хорошая дискуссия по этой теме в старых статьях «Гуру недели» на comp.lang.c ++. moderated здесь .
Соответствующая статья GOTW доступный на веб-сайте Herb Sutter здесь .
Подводя итог:
std::vector::at(size_type pos)
. Что хорошего для стандартной библиотеки, хорошо для меня. _Tmp
все время - вы не хотите этого (на самом деле вам не разрешено использовать их).
– anatolyg
27 July 2017 в 07:44
const
из прототипов функций имеет то преимущество, что вам не нужно изменять файл заголовка, если вы позже захотите отброситьconst
из части реализации. – Michał Górny 9 January 2010 в 12:53const
, где это делает полезную разницу. & Quot; – Deduplicator 9 September 2014 в 17:53const
, когда это возможно; это более выразительно. Когда я читаю чужой код, я использую маленькие индикаторы, подобные этому, чтобы судить о том, как много внимания они уделяют написанию своего кода наряду с такими вещами, как магические числа, комментирование и правильное использование указателей и т. Д. – Ultimater 1 August 2016 в 20:27int getDouble(int a){ ++a; return 2*a; }
Попробуйте это. Конечно,++a
не имеет никакого отношения к этому, но он может i> быть найден там в длинной функции, написанной более чем одним программистом в течение длительного периода времени. Я настоятельно рекомендую написатьint getDouble( const int a ){ //... }
, который будет генерировать ошибку компиляции при поиске++a;
. – dom_beau 27 March 2017 в 03:58