нужно ли const?
void function(const string &);
или
void getname() const;
какая разница между
void function(const string &) и
void function(string)
или
void getname() const и
void getname().
вызываешь функцию синуса long double sin(long double alpha);
Сама по себе идея одной функции для получения нескольких параметров - неверная.
[/QUOTE]
Ой, ну что за детский сад? Называть команду процессора функцией - издевательство. Она приведена как пример, и при том это не мой пример.
Вот мой пример: классическая типичная функция hitscan возвращает точку пересечения прямой с ближайшей к объекту поверхностью, а так же, как побочный продукт вычисления, и ссылочку на сам этот объект, а так же идентификационный номер поверхности, с которой он пересекается, и точку на той поверхности, и по желанию можно задать максимальную дальность следования луча. Подобная функция может использоваться для рей-трейсинга, для трассировки снаряда, для просчета путей ai, для определения столкновений, для выбора объекта...
shoot(float x, float y, float z,
float *hx, float *hy, float *hz, actor *a,
int *face_number, float *face_u, float *face_v, int ray_max_len = 0);
[QUOTE=Green]... лучше потратить время на проверку условий.
зачем?
зачем одной функцией возвращать кучу решений?
Для любителей: SinCosTgCtg(..............)
[/QUOTE]
Допустим наша функция возвращает только координаты точки пересечения. Тогда как узнать с каким объектом пересекается луч?
Лучше раз запустить
je .L4
чем два раза подряд вызывать функцию, делающую поиск в дереве.
[QUOTE=Green]Хм... а индексы на что?
alpha, sinalpha, cosalpha[/QUOTE]И что это меняет? они все три выглядят одинаково, хотя первый параметр передающий, а два других - посылающие.
Вот мой пример: классическая типичная функция hitscan возвращает точку пересечения прямой с ближайшей к объекту поверхностью, а так же, как побочный продукт вычисления, и ссылочку на сам этот объект, а так же идентификационный номер поверхности, с которой он пересекается, и точку на той поверхности, и по желанию можно задать максимальную дальность следования луча. Подобная функция может использоваться для рей-трейсинга, для трассировки снаряда, для просчета путей ai, для определения столкновений, для выбора объекта...
shoot(float x, float y, float z,
float *hx, float *hy, float *hz, actor *a,
int *face_number, float *face_u, float *face_v, int ray_max_len = 0);
Допустим наша функция возвращает только координаты точки пересечения. Тогда как узнать с каким объектом пересекается луч?
Лучше раз запустить
je .L4
чем два раза подряд вызывать функцию, делающую поиск в дереве.
[/QUOTE]
неверный подход, это С-style
видимо ты не привык работать с С++ и ООП
Подумай, что возвращает твоя функция? Как это можно назвать одним словом?
Это можно назвать, например, информацией о месте пересечения:
{
Point;
const Actor*; // или const actor&;
UVcoord;
};
HitInfo* shoot(const Point&, int ray_max_len = 0);
согласись выглядит более читабельно, чем
float *hx, float *hy, float *hz, actor *a,
int *face_number, float *face_u, float *face_v, int ray_max_len = 0);
Допустим для прокладки пути мне нужны только первые три возвращаемых параметра. Ну зачем мне во-первых, создавать всю структуру, и, во-вторых ждать пока функция будет перебирать дерево всех поверхностей фигуры и просчитает точку на этой поверхности?
Создание структуры - опять же вопрос удобства. В ней опять же выбор использовать ссылочки или указатели.
В предложенном мной интерфейсе я могу выставить параметры face_number, face_u и face_v в NULL и не напрягать излишне функцию... То же самое можно в принципе и через структуру сделать - разницы нет. А с сцылочками нужно еще и флаги реализовать, указывая что просчитывать по ходу, а что нет...
Опять же, вопрос вкуса, а на вкус и цвет... Может еще обсудим выделять ли отдельную строку для открывающей фигурной скобки, об уместности goto и об оптимальном размере табуляции. Там вообще можно до потери пульса спорить, но это уж вы без меня...
Хотя конечно интересно узнать какие есть мнения :-) Только пожалуйста конструктивно, без флейма, а то с форума погонят чего доброго...
long double *Sin = 0, long double *Cos = 0) {
if(Sin) {
*Sin = sin(Angle);
}
if(Cos) {
*Cos = cos(Angle);
}
}[/QUOTE]
Фрагмент плохой - даже очень. Слишком большую часть занимают проверки на NULL. Для сравнения, SinCos "как есть" содержит всего несколько ассемблерных команд.
[QUOTE=Green]
class HitInfo
{
Point;
const Actor*; // или const actor&;
UVcoord;
};
HitInfo* shoot(const Point&, int ray_max_len = 0);
[/QUOTE]
А это как вообще может быть :eek: ?
Если объект, на который указывает HitInfo - стековый, то к нему обращаться вне функции нельзя - его уже нет.
Если же объект в "куче", это очень плохой стиль программирования, чреватый утечками памяти. Функции не должны создавать объекты, возвращая результат как указатель.
Допустим для прокладки пути мне нужны только первые три возвращаемых параметра. Ну зачем мне во-первых, создавать всю структуру, и, во-вторых ждать пока функция будет перебирать дерево всех поверхностей фигуры и просчитает точку на этой поверхности?
<skip>
В предложенном мной интерфейсе я могу выставить параметры face_number, face_u и face_v в NULL и не напрягать излишне функцию... То же самое можно в принципе и через структуру сделать - разницы нет. А с сцылочками нужно еще и флаги реализовать, указывая что просчитывать по ходу, а что нет...
[/QUOTE]
Смотри, из твоего предложения: "для прокладки пути мне нужны только первые три возвращаемых параметра" и "функция будет перебирать дерево всех поверхностей фигуры и просчитает точку на этой поверхности", уже можно логически разнести функциональность на две функции: получение точки пересечения (и видимо ссылку на сам объект, исходя из требований твоего предыдущего поста), получение UV-координат:
{
Point;
const Actor*; // или const actor&;
};
HitPoint shoot(const Point&, int ray_max_len = 0);
FacePoint getFacePoint(const Actor&, const Point&);
Кстати, вторая функция вполне может быть методом класса Actor.
[QUOTE=el scorpio]
А это как вообще может быть :eek: ?
Если объект, на который указывает HitInfo - стековый, то к нему обращаться вне функции нельзя - его уже нет.
Если же объект в "куче", это очень плохой стиль программирования, чреватый утечками памяти. Функции не должны создавать объекты, возвращая результат как указатель.[/QUOTE]
А если объект кешированный? :)
Вопрос возвращения объекта зависит от реалищзации.
Ок, для общего успокоения верну его по значению:
HitInfo shoot(const Point&, int ray_max_len = 0);
Вопрос возвращения объекта зависит от реалищзации.
[/QUOTE]
Всё правильно. Возвращать указатель на объект можно в трёх случаях.
1. Указатель на глобальный либо статический объект - функцией не создаётся, соответственно пользователем удаляться не должен. Например, функция ClipBoard(), возвращющая указатель на буфер обмена системы.
2. Указатель на поле класса - даже если объект создаётся данным методом, за удаление его отвечает сам класс.
3. Название метода явно говорит о создании объекта (CreateMessageDialog), после чего даже ежё понятно, что пользователь должен сам удалить полученный объект.
В других случаях возможен "холостой" вызов функции (особенно, если эту функцию использует другой программист, не имеющий доступ к реализации функции), когда результат выполнения отправляется в "никуда". Либо программист не знает о том, что должен сам реализовать удаление полученного объекта.
Результат - утечки памяти.
Как компромис, можно использовать функцию, в которую передаётся ссылка на указатель. Создавая объект, функция изменит этот указатель - и сразу станет понятно, что она делает.
Как компромис, можно использовать функцию, в которую передаётся ссылка на указатель. Создавая объект, функция изменит этот указатель - и сразу станет понятно, что она делает.[/QUOTE]
Слишком запутанно. :)
Я вообще считаю, что ссылка на ссылку это не очень хорошее решение и его по возможности надо избегать.
[/QUOTE]
Ну так, разбей большую функцию со множеством параметров на такие, где поиск объекта будет отдельным методом.
[QUOTE=Svyatozar]
Я предлагаю пример универсального интерфейса скрывающего реализацию, тем самым оставляющий простор для оптимизации в зависимости от доступных средств.[/QUOTE]
на самом деле получается, что это не "универсальный интерфейс", а перегруженный (перенасыщенный) аргументами и возвращаемыми значениями интерфейс.
Оптимизация же, наоборот, будет осложнена тем, что все "в одном флаконе", а это затруднит, как внутреннюю оптимизацию, так и оптимизацию внешнюю (импользования функции).
Пойми, что код
{
if(arg) {
}
if(arg) {
}
if(arg) {
}
}
всегда може быть заменен кодом
func1();
}
if(...) {
func2();
}
if(...) {
func3();
}
если же порядок выполнения известен ещё на этапе компиляции, т.е. то, что ты собираешься делать передавая NULL, то if-ы вовсе уходят:
func3();
такой код значительно проще оптимизировать по любому критерию.
Твоя уверенность в оптимальности максимального разбивания на функции напоминает мне такой случай. Я как-то видел такой код: функция загрузки переменных из массива строк cgi-env для загрузки каждой переменной запускает другую функцию, которая перебирает весь environment, делая strcmp для имени каждой переменной пока не находит нужную. И каждая переменная в этой библиотеке загружалась отдельно вызывая эту функцию. Я не мог поверить глазам!
Когда я отказался от использования этой cgi библиотеки, при загрузке переменных cgi-env я добился увеличения производительности в 200 раз! У меня всего 1 перебор массива строк, распределяющий значения по соответствующим переменным.
Саму передаваемую переменную,- указатель, можешь менять сколько угодно, приращивать, заставлять указывать на другие области памяти, на вызывающий код это никак не повлияет.
Если бы в данном примере не было const, то была бы возможность изменять строку. Как следствие константные строки передать в такую функцию нельзя.
P.S. очередная провокация?[/QUOTE]
сей пост есть чистейший гон, как и другие подробности С++. все кто не верит рекомендую проверить следующий код
{
char* string2 = (char*)string;
string2[0] = 'b';
}
int _tmain(int argc, _TCHAR* argv[])
{
char string[0x20] = "a";
func( string );
return 0;
}
[/QUOTE]
Хорошо. Что именно тебя интересует?
Оптимизация - процесс улучшения системы по конкретному критерию. Так что для начала надо определиться с критерием оптимальности.
В программировании процесс оптимизации начинается с процесса профайлинга на оценочных тестах. Так что для того, что бы утверждать на сколько возрасла производительность, необходимо определить ограничения наложенные на систему, перечислить оценочные тесты и представить результаты профайлинга по этим тестам до и после оптимизации.
Что именно тебя интересует в самом процессе оптимизации?
Я готов тебя научить, тому что знаю сам.
[QUOTE=Svyatozar]
Твоя уверенность в оптимальности максимального разбивания на функции напоминает мне такой случай.
[/QUOTE]
Не "максимальности", а логичности и законченности каждой функции.
В идеале функция должна быть как маленький кирпичик, делающая только то, что вытекает из её названия, получая на вход минимальное количество связанных аргументов и выдающая на выходе конкретное значение, зависящее от этих аргументов.
Твоя уверенность мне тоже многое напоминает, поэтому и пытаюсь показать, как все же правильнее.
{
char* string2 = (char*)string;
string2[0] = 'b';
}
int _tmain(int argc, _TCHAR* argv[])
{
char string[0x20] = "a";
func( string );
return 0;
}
Это типичная ошибка новичков.
Ты слышал что-нибудь о const_cast, который неявно используешь в своем примере ?
char* string2 = (char*)string;
Если ты используешь язык С++, то рекомендую узнать об этом инструменте по-больше. Подробности здесь:
http://www.open-std.org/jtc1/sc22/open/n2356/expr.html#expr.const.cast
http://www.open-std.org/jtc1/sc22/open/n2356/expr.html#expr.cast
Но естественно константный метод не имеет права менять данные класса.
Так что все таки это хороший тон описывать любой публичный метод не меняющий содержимое класса как константный. Ведь было бы странно еслиб у константного объекта мы не могли вызвать метод getName();[/QUOTE]
еще один гон - я спокойно могу написать в методе void getname() const; код изменяющий состояние объекта - по той простой причине что у компилятора нет способа проверить изменяет мой код объект или нет. он конечно может делать это в случае простых перемменых ( int, char ) но если один объект агрегирует в себе другой - и я перегрузил например оператор присваивания - компилятор никак не может проверить изменил я объект или нет.... гыг .... потом проверю это утверждение на пркатике но боюяся что и в этом случае я прав. таким образом const-модификатор функции - полная лажа... а один beep-менеджер меня из за незнания такой фигни на работу не взял.... мол const - єто супер важная примочка .... гыг гыг .... чисто декоративный элемент.... когда же этих beep-менеджеров супер-преподов начнут мочить в сортирах ?
Перед тем, как что-либо так категорично и так эмоционально утверждать, для начала надо действительно всеже проверять.
Ты будешь удивлен возможностями компилятора.
А он действмтельно проверит изменения и сделает это довольно просто: вызываемые методы всех агрегированных объектов должны быть так же константными. :)
P.S. соболезную твоим неудачам в трудоустройстве, но менеджера понимаю.
Ты слышал что-нибудь о const_cast, который неявно используешь в своем примере ?
char* string2 = (char*)string;
Если ты используешь язык С++, то рекомендую узнать об этом инструменте по-больше. Подробности здесь:
http://www.open-std.org/jtc1/sc22/open/n2356/expr.html#expr.const.cast
http://www.open-std.org/jtc1/sc22/open/n2356/expr.html#expr.cast[/QUOTE]
ты ясно написал что нельзя - а я ясно показал что можно - за что удалено было это сообщение ?
Ты будешь удивлен возможностями компилятора.
А он действмтельно проверит изменения и сделает это довольно просто: вызываемые методы всех агрегированных объектов должны быть так же константными. :)
P.S. соболезную твоим неудачам в трудоустройстве, но менеджера понимаю.[/QUOTE]
гыг смотрим код ниже и делаем вывод что Green, как и тот некомпентный менеджер просто пара новичков
{
public:
B() { a[0] = 'a'; a[1] = 0; }
char* Get_a() const
{
char* b = (char*)a;
b[0] = 'f';
}
protected:
char a[0x10];
};
class A
{
public:
A() { a = 10; }
int Get_a() const { return (int)b.Get_a(); }
protected:
B b;
int a;
};
b[0] = 'f';
[/QUOTE]
Производится переопределение "указателя на константу" как "указатель на переменную". Операция возможная, как проезд на красный цвет, и настолько же чреватая "последствиями"
А использовать char* :confused: в программах, особенно в "примерах" не стоит - об этот тип изрядно зубы обламывали люди и поопытнее Вас :(
P.S. Кстати, а что означает код "return (int)b.Get_a();" :eek: ?
Это означает вернуть числовое значение адреса строки, возвращаемое функцией B::Get_a().
class B
{
public:
B() { a[0] = 'a'; a[1] = 0;
printf("%lx inside B constructor: '%s'\n", (long)a, a);
}
char* Get_a() const
{
char* b = (char *)a;
b[0] = 'f';
printf("%lx inside B::Get_a() const: a or f? '%s'\n",
(long)a, a);
return b;
}
protected:
char a[0x10];
};
class A
{
public:
A() { a = 10; }
long Get_a() const { return (long)b.Get_a(); }
protected:
B b;
int a;
};
int main() {
A a;
char *b = (char *)a.Get_a();
printf("%lx char * returned to main(): '%s'\n", (long)b, b);
}
сие выводит что-то вроде:
7fff8368e710 inside B constructor: 'a'
7fff8368e710 inside B::Get_a() const: a or f? 'f'
7fff8368e710 char * returned to main(): 'f'
Зачем? Если требуется узнать адрес символьного массива (для отладки), достаточно привести его к void*. Всё остальное - от лукавого.
7fff8368e710 inside B::Get_a() const: a or f? 'f'
7fff8368e710 char * returned to main(): 'f'
Всё правильно. Оператор const означает, что объект, на который указывает указатель, невозможно изменить, используя этот указатель.
Да, указатель на константный объект можно переопределить как указатель на переменную - собственно говоря, любой указатель можно переопределить как что угодно :( - компилятор это разрешает. Вернее, компилятор "умывает руки", позволяя пользователю всю оставшуюся жизнь отлавливать runtime errors.
const означает, что программист даёт слово, что переданный объект изменяться во время выполнения функции не станет. Если же программист не только переопределяет указатель на константу, но и изменяет этот объект :eek: - тогда его обычно очень больно бьют :( , чтоб впредь подобными безобразиями не страдал.
Ну а на работу подобного "специалиста" я бы тоже брать не стал :D
А использовать char* :confused: в программах, особенно в "примерах" не стоит - об этот тип изрядно зубы обламывали люди и поопытнее Вас :(
P.S. Кстати, а что означает код "return (int)b.Get_a();" :eek: ?[/QUOTE]
я всего лишь хотел показать const вовсе не гарантирует неизменность объекта, злонамеренный код вроде того который привел я спокойно может изменить его, таким образом const - всего лишь декоративный элемент и ровным счетом ничего не гарантирует. такисм образом слова "многоопытных" Green и aks - как и соответсвующая выдержка из учебников по C++ - чистейший гон. ну и кто из нас более опытный ? :D
гыг ... вот интересно зачем приводить его к void* если спокойно можно узнать его адрес и без этого ?
[QUOTE=el scorpio]
Всё правильно. Оператор const означает, что объект, на который указывает указатель, невозможно изменить, используя этот указатель.
Да, указатель на константный объект можно переопределить как указатель на переменную - собственно говоря, любой указатель можно переопределить как что угодно :( - компилятор это разрешает. Вернее, компилятор "умывает руки", позволяя пользователю всю оставшуюся жизнь отлавливать runtime errors.
const означает, что программист даёт слово, что переданный объект изменяться во время выполнения функции не станет. Если же программист не только переопределяет указатель на константу, но и изменяет этот объект :eek: - тогда его обычно очень больно бьют :( , чтоб впредь подобными безобразиями не страдал.[/QUOTE]
таким образом оператор const с практически равным эффектом может быть заменен соответсвующим комментарием, что указывает на то что он абсолютно не является необходимым. я бы бил beep-менеджеров которым не дано этого понять до тех пор пока они бы не дали обещание больше никогда не заниматься программированием и не портить другим гораздо более одаренным людям жизнь.
[QUOTE=el scorpio]
Ну а на работу подобного "специалиста" я бы тоже брать не стал :D[/QUOTE]
ты предсталяешь я бы тя на работу тоже не взял, даже если б твою зарплату платили мне а не тебе.