Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

нужно ли const?

1.8K
14 сентября 2006 года
pod
144 / / 05.04.2006
я очень часто встречаю следующее объявление и тому подобные:

void function(const string &);

или
void getname() const;

какая разница между
void function(const string &) и
void function(string)

или
void getname() const и
void getname().
Страницы:
2
14 сентября 2006 года
squirL
5.6K / / 13.08.2003
насколько я помню, при указании const запрещается менять указуемый объект. т. е. в случае

void function(const string & str)

ты не сможешь внутри function сделать str = "abcd";
1.9K
14 сентября 2006 года
[*]Frosty
278 / / 17.06.2006
 
Код:
void getname() const;
- константый метод. const говорит о том, что данный метод не может изменять значений членов-данных класса.
1.8K
14 сентября 2006 года
pod
144 / / 05.04.2006
[QUOTE=squirL]насколько я помню, при указании const запрещается менять указуемый объект. т. е. в случае

void function(const string & str)

ты не сможешь внутри function сделать str = "abcd";[/QUOTE]

да я это понимаю но почему давать функции string & если его не надо менять а потом приписывать const?
дадим прямо string?
3
14 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=pod]да я это понимаю но почему давать функции string & если его не надо менять а потом приписывать const?
дадим прямо string?[/QUOTE]
Потому, что если просто передавать string, то будет создан временный объект, а это нежелательно по нескольким причинам:
1) увеличивает время выполнения операции, т.к. вызывается конструктор копирования,
2) в общем случае приводит к фрагментации памяти,
3) в некоторых случаях приводит к неверной логике работы или даже к ошибочным ситуациям, например, когда создание временного объекта приводит к попытке залочить уже залоченный ресурс, к примеру, открыть на запись уже открытый для записи файл.
240
15 сентября 2006 года
aks
2.5K / / 14.07.2006
Ну и плюс запись вида:
 
Код:
void function(const string & str)

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

А у константного объекта (скажем переданного в другой метод описанным выше способом) можно вызывать только константные методы типа такого:
 
Код:
void getname() const;

Но естественно константный метод не имеет права менять данные класса.
Так что все таки это хороший тон описывать любой публичный метод не меняющий содержимое класса как константный. Ведь было бы странно еслиб у константного объекта мы не могли вызвать метод getName();
1.8K
15 сентября 2006 года
pod
144 / / 05.04.2006
Green
aks
спосибо друзья сейчас всё понятно.
это мне многое прояснило.
3.3K
15 сентября 2006 года
ShadyMan
191 / / 15.07.2006
[QUOTE=pod]это мне многое прояснило.[/QUOTE]
Хорошо тебе, pod. А вот мне всё равно непонятно. Вот, например, у нас функция void some_func(const char *str). В ней мы не можем производить запись в переменную str. Так? Ну и что это нам даёт? А если бы не было const и запись в str была разрешена, что бы это изменило? Ведь функции сообщается не сама переменная, а её копия, так что никакого сбоя в программе вроде бы быть не должно.
Объясните, пожалуйста, те, кто ещё не вызверился на меня.
3
15 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=ShadyMan]Хорошо тебе, pod. А вот мне всё равно непонятно. Вот, например, у нас функция void some_func(const char *str). В ней мы не можем производить запись в переменную str. Так? Ну и что это нам даёт? А если бы не было const и запись в str была разрешена, что бы это изменило? Ведь функции сообщается не сама переменная, а её копия, так что никакого сбоя в программе вроде бы быть не должно.
Объясните, пожалуйста, те, кто ещё не вызверился на меня.[/QUOTE]
В данном случае передается указатель на константную строку (на строку, а не на её копию). Т.е. читать то ты строку можешь, а изменять её нет.
Саму передаваемую переменную,- указатель, можешь менять сколько угодно, приращивать, заставлять указывать на другие области памяти, на вызывающий код это никак не повлияет.

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

P.S. очередная провокация?
3.0K
15 сентября 2006 года
Мerlin
267 / / 25.07.2006
2ShadyMan
Тебе уже так объяснили, что если даже и теперь не понятно, то я бы на твоем месте все равно сказал, бы, что: "всем спасибо, все ясно". Но чтоб лучше понять, откуда упал этот const, советую прочитать из книги Дж.Хеллер-"Ловушка 22" главу о Майор Майор(ту часть в которой он доврался до власти и установил правила в столовой).
1.9K
15 сентября 2006 года
SABROG
242 / / 26.01.2006
В продолжении темы хотелось бы для себя уяснить тоже. Если углубиться немного в VCL. Есть такая запись:

 
Код:
{
AnsiString txt = "Hello, World!";
Show(txt);
}
void Show(AnsiString txt){
ShowMessage(txt);
}


AnsiString - объект класса. Значит если я указываю его в параметрах, то перед вызовом создасться временный объект класа AnsiString, куда скопируется строка txt ?

Предположим я не буду менять строку, но хочу оптимизации. Если я напишу так:

 
Код:
AnsiString txt = "Hello, World!";
Show(txt);
}
void Show(const AnsiString txt){
ShowMessage(txt);
}

Временный класс не создастся и я буду работать с реальным указателем ?
3
15 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=SABROG]
Предположим я не буду менять строку, но хочу оптимизации. Если я напишу так:

 
Код:
AnsiString txt = "Hello, World!";
Show(txt);
}
void Show(const AnsiString txt){
ShowMessage(txt);
}

Временный класс не создастся и я буду работать с реальным указателем ?[/QUOTE]
void Show(const AnsiString[COLOR=RED]&[/COLOR] txt)

ты будешь работать с объектом созданным в вызывающем коде
1.9K
15 сентября 2006 года
SABROG
242 / / 26.01.2006
А если просто:

 
Код:
void __fastcall TForm1::Button6Click(TObject *Sender)
{
AnsiString txt = "Hello, World!";
Msg(&hmm);        
}

void __fastcall TForm1::Msg(AnsiString *txt)
{
ShowMessage(*txt);
}

Тоже оптимально ? Тогда значит const в принципе нужен только для того, чтобы контролировать изменяется ли объект или нет ?
3
15 сентября 2006 года
Green
4.8K / / 20.01.2000
Я приведу два примера:
 
Код:
void __fastcall TForm1::Button6Click(TObject *Sender)
{
    Mss(NULL);        
}

void __fastcall TForm1::Msg(AnsiString *txt)
{
    ShowMessage(*txt);
}

 
Код:
void __fastcall TForm1::Button6Click(TObject *Sender)
{
    const AnsiString hmm = "Hello, World!";
    Mss(hmm);
}

void __fastcall TForm1::Msg(AnsiString& txt)
{
    ShowMessage(txt);
}

Думаю, понятно что к чему?
Если нет, могу объяснить.
3.0K
16 сентября 2006 года
Мerlin
267 / / 25.07.2006
[QUOTE=Green]Я приведу два примера:
 
Код:
void __fastcall TForm1::Button6Click(TObject *Sender)
{
    Mss(NULL);        
}

void __fastcall TForm1::Msg(AnsiString *txt)
{
    ShowMessage(*txt);
}

 
Код:
void __fastcall TForm1::Button6Click(TObject *Sender)
{
    const AnsiString hmm = "Hello, World!";
    Mss(hmm);
}

void __fastcall TForm1::Msg(AnsiString& txt)
{
    ShowMessage(txt);
}

[color=red]Думаю, понятно что к чему?[/color][/QUOTE]
Не а. Глухо как в танке. :(
Цитата:
Если нет, могу объяснить.

Please :)
В общем-то, я и мой компилятор заблудились между Mss и Msg. А об Mss(NULL) и ShowMessage(*txt); вообще промолчим.

1.9K
16 сентября 2006 года
SABROG
242 / / 26.01.2006
[QUOTE=Green]Думаю, понятно что к чему?
Если нет, могу объяснить.[/QUOTE]
Ну в первом примере ты впихнул нулевой указатель, намерянно ;)
Access Violation

Во втором примере ты объявил объект класса AnsiString константным и явно его проинициализировал. Если его не инициализировать, то выведется пустое окно. Вопрос вот в чем, могу ли я добиться оптимизации без объявляения const ? Я думаю что могу, достаточно передать указатель вместо объекта. Проблема может возникнуть только, если у меня многопоточное приложение и объект класса в одном из потоке будет уничтожен или изменен.

2Merlin: моя опечатка, в данном случае Mss=Msg ;)
3
16 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=SABROG]Ну в первом примере ты впихнул нулевой указатель, намерянно ;)
Access Violation
[/QUOTE]
Да, конечно.
Этим я хотел показать, чем собственно передача по ссылке отличается от передачи по указателю. Ссылка не может быть нулевой, а сл-но исключаются вариант некорректного указания объекта, а сл-но можно исключить и проверку указателя на валидность, которая в принципе желательна при использовании указателя (хотя бы assert в debug-mode должен быть).

[QUOTE=SABROG]
Во втором примере ты объявил объект класса AnsiString константным и явно его проинициализировал. Если его не инициализировать, то выведется пустое окно.
[/QUOTE]
Нет. Во втором примере я показал, что константные объекты не могут быть переданы в функцию, которая принимает неконстантные объекты по ссылке. Т.о. const не только чтобы "контролировать изменяется объект или нет", но и для того, что бы функция могла принимать константные объекты.

[QUOTE=SABROG]
Вопрос вот в чем, могу ли я добиться оптимизации без объявляения const ? Я думаю что могу, достаточно передать указатель вместо объекта.
[/QUOTE]
"Оптимизация" - это понятие бессмысленное без понятия "критерий".
Оптимизация бывает по производительности (скорости выполнения), по используемому объему памяти, по размеру исполняемого файла и т.п.

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

[QUOTE=SABROG]
Проблема может возникнуть только, если у меня многопоточное приложение и объект класса в одном из потоке будет уничтожен или изменен.
[/QUOTE]
При совместном использовании одного ресурса разными потоками требуется синхронизация на системном уровне. Здесь никакие конструкции языка не влияют, т.е. const не поможет.
Здесь требуются системный объекты синхронизации (критические секции, мьютексы, семафоры и т.д.)
Есть различные трюки, позволяющие не использовать системных объектов синхронизации, но они опять же выходят за рамки языка.
1.9K
16 сентября 2006 года
SABROG
242 / / 26.01.2006
[QUOTE=Green]"Оптимизация" - это понятие бессмысленное без понятия "критерий".
[/quote]
Я о той оптимизации, о которой было упомянуто ранее. Критерием для нее служит скорость и расход памяти. Т.е. при передачи объекта в функцию - выделяется память под временный класс. Не знаю, скорее всего выполняется и его конструктор. А при выходе из функции - деструктор. Соответственно теряем память и процессорное время. Чтобы этого избежать - лучше передавать указатель. Однако бывают ситуации, когда надо активно работать с переданным объектом (удалять, вставлять элементы), но чтобы при выходе из функции в вызывающей функции он оставался прежним, тогда да, это оправданно.
В общем это уже к const не относится.

Для тех кто читает и не понял, чем отличается прототип:
 
Код:
void Func(AnsiString);

от
 
Код:
void Func(AnsiString *);


Пример того как при передаче параметра полностью копируется объект:
Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString txt = "Text";
CopyTest(txt);
ShowMessage(txt);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::CopyTest(AnsiString txt)
{
txt.Delete(1,txt.Length());
ShowMessage(txt);
}


а это пример того, как он не копируется :)
Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString txt = "Text";
CopyTest(txt);
ShowMessage(txt);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::CopyTest(AnsiString &txt)
{
txt.Delete(1,txt.Length());
ShowMessage(txt);}
3.3K
16 сентября 2006 года
ShadyMan
191 / / 15.07.2006
[QUOTE=Green]Если бы в данном примере не было const, то была бы возможность изменять строку.[/QUOTE]
Ну вот теперь понятно. Спасибо. А вот ещё интересно, func(int &i) - это только в С++ работает? В С, я так понял, если я хочу получить доступ к самому объекту, а не к его копии, придётся писать func(int *i), а потом, каждый раз обращаясь к содержимому i, постоянно использовать разадресацию?
[QUOTE=Green]P.S. очередная провокация?[/QUOTE]:D :D :D
3
16 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=SABROG]Не знаю, скорее всего выполняется и его конструктор. А при выходе из функции - деструктор.
[/QUOTE]
Вызывается однозначно.
3
16 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=ShadyMan]Ну вот теперь понятно. Спасибо. А вот ещё интересно, func(int &i) - это только в С++ работает?[/QUOTE]
Да, ссылки естьв С++, в С их нет.
309
20 сентября 2006 года
el scorpio
1.1K / / 19.09.2006
Объясняю подробно

Параметры в функцию можно передавать тремя способами: по значению, по ссылке (&) и по указателю (*). Ссылка и указатель содержат адрес объекта, разница между ними в том, что значением ссылки является значение объекта.

Ниже описаны основные способы передачи параметров функциям
Код:
Function1 (int Index)
{
}

Function2 (const int Index)
{
}

Function3 (int &Index)
{
}

Function4 (const AnsiString &Str)
{
}

Function5 (TStringList *List)
{
}

Function6 (TStringList const *List)
{
}

Function7 (const TStringList *List)
{
}

TCustomObject::Method8 () const
{
}


1. Передаётся значение путём копирования. Изменение локальной переменной не изменит внешнюю.
2. Передаётся значение путём копирования. Изменение локальной переменной невозможно. Практически никогда не используется.
3. Передаётся ссылка на объект. Изменение локальной переменной изменит внешнюю. Нельзя передавать константные значения и выражения.
4. Передаётся константная ссылка на объект. Изменение локальной переменной изменит невозможно. Можно передавать константные значения и выражения.
5. Передаётся указатель на объект. Изменение локальной переменной на адрес другого объекта возможно. Изменение значения указываемого объекта изменит этот объект. Нельзя передавать адреса констант и выражений
6. Передаётся константный указатель на объект. Изменение локальной переменной на адрес другого объекта возможно. Изменение значения указываемого объекта изменит этот объект. Нельзя передавать адреса констант и выражений
7. Передаётся указатель на константный объект. Изменение локальной переменной на адрес другого объекта возможно. Изменение значения указываемого объекта недопустими. Можно передавать адреса констант и выражений.
8. Вызывается константный метод объекта. Данный метод не может изменять свои поля данных и вызывать неконстантные методы для самого себя. Такой метод может вызываться для константного объекта. Неконстантные методы для константных объектов вызываться не могут.

Выводы.
1. Любой метод класса, который не изменяет свои внутренние данные должен быть объявлен как константный. К сожалению, разработчики объектов VCL это правило не учли :( (см. 8)
2. Любой объект из "кучи", если не изменяется во время работы функции, должен передаваться указателем на константу (см. 7) для того, чтобы программист мог понять это по описанию функции.
3. Любой объект из стека, имеющий сложную структуру (например, struct), если не изменяется во время работы функции, должен передаваться константной ссылкой (см. 4) для ускорения работы программы.
4. Если объект передаётся неконстантной ссылкой либо указателем, значит он изменяется в процессе выполнения функции. Неконстантные ссылки используются для возвращения дополнительного результата функции.
5. Если локальное значение объекта в процессе работы функции изменяется, но это изменение не должно быть влиять на работу программы, объект передаётся путём копирования (см. 1)

Способы вызова 2 и 6 используются крайне редко, слово const здесь не несёт никакой смысловой нагрузки для основной программы, и означает только, что локальное значение переданного параметра (которое будет утеряно при выходе из функции) не может изменяться во время её работы:confused:
5.4K
20 сентября 2006 года
Svyatozar
221 / / 11.09.2006
Резюмирую для чего нужен const.
компилятор не пропустит этого:

 
Код:
int twice(int *a) {
    return *a + *a;
}

main() {
    const int a = 8;
    return twice(&a);
}


а это пройдет:

 
Код:
int twice(const int *a) {
    return *a + *a;
}

main() {
    const int a = 8;
    return twice(&a);
}


переменные не объявленные const пройдут в обоих случаях
5.4K
20 сентября 2006 года
Svyatozar
221 / / 11.09.2006
И еще важно помнить:
 
Код:
_____Значение по адресу ---|
                      |    ______________________|
                      | ___|__
  ar эквивалентно  *(ar + i)
& ar эквивалентно   (ar + i)
| ^^^^^              
|   |--------------------------|
|________адрес значения--------|


указатель на функцию типа double, с аргументом int:
double (*pf)(int);

функция, возвращающая указатель на double:
double *pf(int);

_____________________________________________

указатель на константу целого типа:
int const *ptr;
эквивалентно выражению:
const int *ptr


константа, указывающая на переманную целого типа:
int *const ptr;
НЕ эквивалентно выражению const *int ptr; <- это вообще не имеет смысла


константа, указывающая на константу целого типа:
int const *const ptr;
зквивалентно выражению:
const int *const ptr;
309
22 сентября 2006 года
el scorpio
1.1K / / 19.09.2006
Дополняю свой пост
Параметры-указатели используются только для объектов, традиционно располагающихся в "куче", а также для простых линейных массивов.
"Func (const long double *pFloat)" имеет смысл только для массива. Для работы с одним значением лучше использовать ссылку - не надо будет каждый раз выполнять операцию обращения по адресу "*" (неуклюжее слово "разыменование" я не приемлю :))

Параметры-ссылки используются только для объектов, традиционно располагающихся в стеке.
Написание "Func (const TStringList &rList)" стилистически абсурдно.

А вот ситуация, когда передача константного значения может быть оправдана: "Func (const AnsiString Str)"
Дело в том, что в AnsiString используется хитрый алгоритм управления памятью. При операциях присваивания/копирования значений, передаётся только указатель на символьный массив другого объекта. При удалении объекта счётчик указателей на массив уменьшается. Сам же массив удаляется, когда счётчик ссылок обнуляется.
Сам же массив копируется только когда производится изменение строки, которую используют одновременно несколько объектов. const запрещает случайно вызвать функцию изменения объекта.

Что же касается изменяемых ссылок, то на их использование тоже есть ограничение. Компилятор выдаст предупреждение для следующего кода
 
Код:
Func (int &Value)
{
}
//.....
int a,b;
Func (a+b); //warning temporary value

Дело в том, что результат выражения "a+b" записывается во временную неименованную переменную, которая удаляется из стека после выполнения функции. Соответственно, результат работы функции, изменённый по ссылке на временное значение, будет утерен.
А вот код "Func (c = a+b)" сработает, потому что фунция будет работать с определённым значением "c"

Аналогично не сработает следующий код
 
Код:
double Sin, Cos;
double Angle = 3.14;
SinCos (Angle, Sin, Cos);

Функция SinCos оперирует с аргументами типа long double, к которому придётся привести параметры. Результаты приведения будут помещены во временные неименованые переменные. Но если для первого параметра - константной ссылке - это не страшно, то изменение прочих (неконстантных) параметров уйдёт в "никуда".
5.4K
22 сентября 2006 года
Svyatozar
221 / / 11.09.2006
Лично я передачи аргументов по ссылке стараюсь избегать. Они необходимы для перегрузки операторов, а во всех остальных случаях только сбивают с толку, добавляя путаницу. Очень советую использовать указатели где это только возможно.

Ну и внутри функций иногда для сокращения записи использую ссылки как алиасы.
5.4K
22 сентября 2006 года
Svyatozar
221 / / 11.09.2006
Лично я передачи аргументов по ссылке стараюсь избегать. Они необходимы для перегрузки операторов, а во всех остальных случаях только сбивают с толку, добавляя путаницу. Очень советую использовать указатели где это только возможно.

Ну и внутри функций иногда для сокращения записи использую ссылки как алиасы.
240
22 сентября 2006 года
aks
2.5K / / 14.07.2006
И очень зря. Ссылки как раз и созданны для упрощения их использования и более логичны в ООП чем указатели. Так что передавать в методы значения как руз лучше по ссылками, где это возможно. Хотя возможно не всегда - указатели тоже нужны.
5.4K
22 сентября 2006 года
Svyatozar
221 / / 11.09.2006
С точки зрения проектирования интерфейсов, путаница может возникнуть вот в чем: допустим класс содержит как деструктивные, так и недеструктивные функции. Простой пример навскидку: функция возвращает частное от деления, а остаток помещает в a:
 
Код:
int divide(int &a, int b) {
    int result = a / b;
    a = a % b;
    return result;
}


теперь, когда я вижу:

c = divide(a, b);

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

Поэтому я бы объявил подобную функцию так:
 
Код:
int divide(int *a, int b) {
    int result = a / b;
    *a = a % b;
    return result;
}


и при вызове сразу видно что изменяется а что нет:

c = divide(&a, b);
240
22 сентября 2006 года
aks
2.5K / / 14.07.2006
Во первых не надо так проектировать функции как тут - это действительно проектирование с ошибкой.
Да и потом есть еще и передача константных объектов.

На Java приходилось программировать?
5.4K
22 сентября 2006 года
Svyatozar
221 / / 11.09.2006
[QUOTE=aks]Во первых не надо так проектировать функции как тут - это действительно проектирование с ошибкой.[/QUOTE]
В чем ошибка-то?
[QUOTE=aks]Да и потом есть еще и передача константных объектов.[/QUOTE]
Дык с константными объектами-то и проблем нет...
[QUOTE=aks]На Java приходилось программировать?[/QUOTE]
Нет, к счастью пока не приходилось :D
3
22 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=Svyatozar]В чем ошибка-то?
[/QUOTE]
Функциям надо давать говорящие имена.
Функция не должна изменять входных значений (поэтому значения лучше и передавать как константные), если она именно для этого не предназначена.
Приведенная тобой функция должна быть на самом деле двумя функциями: "результат целочисленного деления" и "остаток целочисленного деления".

[QUOTE=Svyatozar]
 
Код:
int divide(int *a, int b) {
    int result = a / b;
    *a = a % b;
    return result;
}

[/QUOTE]
Наверное все же:
 
Код:
int divide(int *a, int b) {
    int result = *a / b;
    *a = *a % b;
    return result;
}

Тогда где проверка (хотябы в режиме отладки), что указатель валиден?
5.4K
22 сентября 2006 года
Svyatozar
221 / / 11.09.2006
[QUOTE=Green]Наверное все же:
[/QUOTE]
Благодарю за поправку.

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

int divide_rem(int &remainder, int a, int b);

Все равно при вызове будет что-то такое:
a3 = divide_rem(my_rem, a1, a2);
Ну это к примеру опять же. Так вот здесь не так очевидно что происходит, то есть наглядность кода страдает. В то время как:
a3 = divide_rem(&my_rem, a1, a2);
тут сразу видно что в my_rem возвращаяется какое-то значение. Просто для этого надо использовать указатель в объявлении функции:

int divide_rem(int *remainder, int a, int b);

и соответственно изменить тело функции. Все это лишь вопрос стиля и наглядности.
309
23 сентября 2006 года
el scorpio
1.1K / / 19.09.2006
[QUOTE=Svyatozar]
int divide_rem(int &remainder, int a, int b);

Все равно при вызове будет что-то такое:
a3 = divide_rem(my_rem, a1, a2);
Ну это к примеру опять же. Так вот здесь не так очевидно что происходит, то есть наглядность кода страдает. В то время как:
a3 = divide_rem(&my_rem, a1, a2);
[/QUOTE]
Для наглядности, параметры, которые изменяются по ссылке, нужно помещать в конце списка
 
Код:
int divide_rem (int a, int b, int &rem);

Тогда rem стилистически и логически будет восприниматься, как результат обработки первых двух параметров. Такое правило действует для всех функций VCL.
Кроме того, при написании кода, IDE имеет привычку высвечивать типы и имена аргументов функции.
5.4K
23 сентября 2006 года
Svyatozar
221 / / 11.09.2006
[QUOTE=el scorpio]Для наглядности, параметры, которые изменяются по ссылке, нужно помещать в конце списка[/QUOTE]
Странно, а я думал что конец списка для необязательных параметров...
[QUOTE=el scorpio]
 
Код:
int divide_rem (int a, int b, int &rem);
[/QUOTE]
Да, но при вызове далеко не очевидно что функция вообще передает результат по ссылке!
[QUOTE=el scorpio]Тогда rem стилистически и логически будет восприниматься, как результат обработки первых двух параметров. Такое правило действует для всех функций VCL.[/QUOTE]
Можно пример? А то я не знаком с этой библиотекой.
[QUOTE=el scorpio]Кроме того, при написании кода, IDE имеет привычку высвечивать типы и имена аргументов функции.[/QUOTE]
При написании-то понятно, а при чтении?
309
24 сентября 2006 года
el scorpio
1.1K / / 19.09.2006
[QUOTE=Svyatozar]Можно пример? А то я не знаком с этой библиотекой.[/QUOTE]
SinCos (const long double &Angle, long double &Sin, long double &Cos)

Непонять что делает - сложно :D

А для чтения кода нужно давать изменяемым переменным понятные имена
5.4K
24 сентября 2006 года
Svyatozar
221 / / 11.09.2006
[QUOTE=el scorpio]SinCos (const long double &Angle, long double &Sin, long double &Cos)

Непонять что делает - сложно :D

А для чтения кода нужно давать изменяемым переменным понятные имена[/QUOTE]
Я не любитель жарких споров на тему стиля, но лично я бы оформил подобную функцию так:

sincos(long double alpha, long double *sin_alpha, long double *cos_alpha);
3
24 сентября 2006 года
Green
4.8K / / 20.01.2000
А я бы так:
long double sin(long double alpha);
long double cos(long double alpha);
309
24 сентября 2006 года
el scorpio
1.1K / / 19.09.2006
Svyatozar
Можешь хоть всю VCL переписать под себя :). Только не забудь в каждой функции добавить проверку указателей на NULL :D

[quote=Green]
А я бы так:
long double sin(long double alpha);
long double cos(long double alpha);
[/quote]
Собственно, именно так и объявлено в "Math.h" (просьба не путать файл с "Math.hpp")
5.4K
24 сентября 2006 года
Svyatozar
221 / / 11.09.2006
[QUOTE=el scorpio]Svyatozar
Можешь хоть всю VCL переписать под себя :). Только не забудь в каждой функции добавить проверку указателей на NULL :D[/QUOTE]
Да, каждый указатель нужно проверять на ноль. Дык специальное значение указателя - это же его большое приемущество! К примеру:

sincos(long double alpha, long double *sin_alpha = 0, long double *cos_alpha = 0) {
if(sin_alpha) {
sin_alpha = sin(alpha);
}
if(cos_alpha) {
cos_alpha = cos(alpha);
}

Допустим, мне нужен только косинус:

long double cos_alpha;
sincos(alpha, 0, &cos_alpha);

или нужен только синус:

long double sin_alpha;
sincos(alpha, &sin_alpha);

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

Да, кстати, о прозрачности массивов:
Код:
#include <math.h>

inline void SinCos(long double Angle,
        long double *Sin = 0, long double *Cos = 0) {
    if(Sin) {
        *Sin = sin(Angle);
    }
    if(Cos) {
        *Cos = cos(Angle);
    }
}

int main() {
    long double alpha[5] = {.3, 2.1, 1.0, .9, .2};
    long double sinalpha[5], cosalpha[5];
    for(int i = 5; --i >= 0; ) {
        SinCos(*(alpha + i), sinalpha + i, cosalpha + i);
    }
    return 0;
}

А со ссылочками было бы я полагаю
SinCos(*(alpha + i), *(sinalpha + i), *(cosalpha + i));
так что ли? Где тут видно что вообще что-то возвращается? Что передается а что возвращается? Сплошное недоразумение на мой взгляд...
3
24 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=Svyatozar]
Допустим, мне нужен только косинус:
[/QUOTE]
вызываешь функцию косинуса long double cos(long double alpha);

[QUOTE=Svyatozar]
или нужен только синус:
[/QUOTE]
вызываешь функцию синуса long double sin(long double alpha);

Сама по себе идея одной функции для получения нескольких параметров - неверная.

[QUOTE=Svyatozar]
Конечно такой пустяк как sincos - это не лучший пример. Но когда у функции аргументов поболе (пусть даже в структуре) - при помощи NULL-указателя можно гибко задавать какие значения нужны, а на вычисления каких не надо тратить времени.
[/QUOTE]
... лучше потратить время на проверку условий.
зачем?
зачем одной функцией возвращать кучу решений?
Для любителей: SinCosTgCtg(..............)

[QUOTE=Svyatozar]
А со ссылочками было бы я полагаю
SinCos(*(alpha + i), *(sinalpha + i), *(cosalpha + i));
так что ли? Где тут видно что вообще что-то возвращается? Что передается а что возвращается? Сплошное недоразумение на мой взгляд...[/QUOTE]
Хм... а индексы на что?
alpha, sinalpha, cosalpha
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог