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

Ваш аккаунт

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

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

Подписчиков: -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().
Страницы:
5.4K
24 сентября 2006 года
Svyatozar
221 / / 11.09.2006
[QUOTE=Green]вызываешь функцию косинуса long double cos(long double alpha);


вызываешь функцию синуса 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]
Допустим наша функция возвращает только координаты точки пересечения. Тогда как узнать с каким объектом пересекается луч?
Лучше раз запустить
 
Код:
testl   %eax, %eax
    je  .L4

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

[QUOTE=Green]Хм... а индексы на что?
alpha, sinalpha, cosalpha[/QUOTE]И что это меняет? они все три выглядят одинаково, хотя первый параметр передающий, а два других - посылающие.
3
24 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=Svyatozar]
Вот мой пример: классическая типичная функция 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);


Допустим наша функция возвращает только координаты точки пересечения. Тогда как узнать с каким объектом пересекается луч?
Лучше раз запустить
 
Код:
testl   %eax, %eax
    je  .L4

чем два раза подряд вызывать функцию, делающую поиск в дереве.
[/QUOTE]
неверный подход, это С-style
видимо ты не привык работать с С++ и ООП
Подумай, что возвращает твоя функция? Как это можно назвать одним словом?
Это можно назвать, например, информацией о месте пересечения:
 
Код:
class HitInfo
{
    Point;
    const Actor*;      // или const actor&;
    UVcoord;
};

HitInfo*  shoot(const Point&, int ray_max_len = 0);

согласись выглядит более читабельно, чем
 
Код:
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);
5.4K
25 сентября 2006 года
Svyatozar
221 / / 11.09.2006
Не совсем то же самое, кстати, но я понял твою мысль.

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

Создание структуры - опять же вопрос удобства. В ней опять же выбор использовать ссылочки или указатели.

В предложенном мной интерфейсе я могу выставить параметры face_number, face_u и face_v в NULL и не напрягать излишне функцию... То же самое можно в принципе и через структуру сделать - разницы нет. А с сцылочками нужно еще и флаги реализовать, указывая что просчитывать по ходу, а что нет...

Опять же, вопрос вкуса, а на вкус и цвет... Может еще обсудим выделять ли отдельную строку для открывающей фигурной скобки, об уместности goto и об оптимальном размере табуляции. Там вообще можно до потери пульса спорить, но это уж вы без меня...

Хотя конечно интересно узнать какие есть мнения :-) Только пожалуйста конструктивно, без флейма, а то с форума погонят чего доброго...
309
25 сентября 2006 года
el scorpio
1.1K / / 19.09.2006
[QUOTE=Svyatozar]inline void SinCos(long double Angle,
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 - стековый, то к нему обращаться вне функции нельзя - его уже нет.
Если же объект в "куче", это очень плохой стиль программирования, чреватый утечками памяти. Функции не должны создавать объекты, возвращая результат как указатель.
3
25 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=Svyatozar]
Допустим для прокладки пути мне нужны только первые три возвращаемых параметра. Ну зачем мне во-первых, создавать всю структуру, и, во-вторых ждать пока функция будет перебирать дерево всех поверхностей фигуры и просчитает точку на этой поверхности?
<skip>
В предложенном мной интерфейсе я могу выставить параметры face_number, face_u и face_v в NULL и не напрягать излишне функцию... То же самое можно в принципе и через структуру сделать - разницы нет. А с сцылочками нужно еще и флаги реализовать, указывая что просчитывать по ходу, а что нет...
[/QUOTE]
Смотри, из твоего предложения: "для прокладки пути мне нужны только первые три возвращаемых параметра" и "функция будет перебирать дерево всех поверхностей фигуры и просчитает точку на этой поверхности", уже можно логически разнести функциональность на две функции: получение точки пересечения (и видимо ссылку на сам объект, исходя из требований твоего предыдущего поста), получение UV-координат:
 
Код:
class HitPoint
{
    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);
309
25 сентября 2006 года
el scorpio
1.1K / / 19.09.2006
[QUOTE=Green]А если объект кешированный? :)
Вопрос возвращения объекта зависит от реалищзации.
[/QUOTE]
Всё правильно. Возвращать указатель на объект можно в трёх случаях.
1. Указатель на глобальный либо статический объект - функцией не создаётся, соответственно пользователем удаляться не должен. Например, функция ClipBoard(), возвращющая указатель на буфер обмена системы.
2. Указатель на поле класса - даже если объект создаётся данным методом, за удаление его отвечает сам класс.
3. Название метода явно говорит о создании объекта (CreateMessageDialog), после чего даже ежё понятно, что пользователь должен сам удалить полученный объект.
В других случаях возможен "холостой" вызов функции (особенно, если эту функцию использует другой программист, не имеющий доступ к реализации функции), когда результат выполнения отправляется в "никуда". Либо программист не знает о том, что должен сам реализовать удаление полученного объекта.
Результат - утечки памяти.

Как компромис, можно использовать функцию, в которую передаётся ссылка на указатель. Создавая объект, функция изменит этот указатель - и сразу станет понятно, что она делает.
3
25 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=el scorpio]
Как компромис, можно использовать функцию, в которую передаётся ссылка на указатель. Создавая объект, функция изменит этот указатель - и сразу станет понятно, что она делает.[/QUOTE]
Слишком запутанно. :)
Я вообще считаю, что ссылка на ссылку это не очень хорошее решение и его по возможности надо избегать.
5.4K
25 сентября 2006 года
Svyatozar
221 / / 11.09.2006
А допустим нужны только координаты точки пересечения и UV координаты, которые можно узнать мгновенно полностью через функции OpenGL - тогда нафига вообще искать объект, напрягая базу данных и процессор? Я предлагаю пример универсального интерфейса скрывающего реализацию, тем самым оставляющий простор для оптимизации в зависимости от доступных средств.
3
25 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=Svyatozar]А допустим нужны только координаты точки пересечения и UV координаты, которые можно узнать мгновенно полностью через функции OpenGL - тогда нафига вообще искать объект, напрягая базу данных и процессор?
[/QUOTE]
Ну так, разбей большую функцию со множеством параметров на такие, где поиск объекта будет отдельным методом.

[QUOTE=Svyatozar]
Я предлагаю пример универсального интерфейса скрывающего реализацию, тем самым оставляющий простор для оптимизации в зависимости от доступных средств.[/QUOTE]
на самом деле получается, что это не "универсальный интерфейс", а перегруженный (перенасыщенный) аргументами и возвращаемыми значениями интерфейс.
Оптимизация же, наоборот, будет осложнена тем, что все "в одном флаконе", а это затруднит, как внутреннюю оптимизацию, так и оптимизацию внешнюю (импользования функции).

Пойми, что код
Код:
Result func(args)
{
   if(arg) {
   }

   if(arg) {
   }

   if(arg) {
   }
}

всегда може быть заменен кодом
Код:
if(...) {
    func1();
  }

   if(...) {
    func2();
   }

   if(...) {
    func3();
   }

если же порядок выполнения известен ещё на этапе компиляции, т.е. то, что ты собираешься делать передавая NULL, то if-ы вовсе уходят:
 
Код:
func1();
    func3();

такой код значительно проще оптимизировать по любому критерию.
5.4K
25 сентября 2006 года
Svyatozar
221 / / 11.09.2006
Научи-ка меня оптимизировать код :D

Твоя уверенность в оптимальности максимального разбивания на функции напоминает мне такой случай. Я как-то видел такой код: функция загрузки переменных из массива строк cgi-env для загрузки каждой переменной запускает другую функцию, которая перебирает весь environment, делая strcmp для имени каждой переменной пока не находит нужную. И каждая переменная в этой библиотеке загружалась отдельно вызывая эту функцию. Я не мог поверить глазам!

Когда я отказался от использования этой cgi библиотеки, при загрузке переменных cgi-env я добился увеличения производительности в 200 раз! У меня всего 1 перебор массива строк, распределяющий значения по соответствующим переменным.
351
26 сентября 2006 года
PitxBull
633 / / 22.12.2004
[QUOTE=Green]В данном случае передается указатель на константную строку (на строку, а не на её копию). Т.е. читать то ты строку можешь, а изменять её нет.
Саму передаваемую переменную,- указатель, можешь менять сколько угодно, приращивать, заставлять указывать на другие области памяти, на вызывающий код это никак не повлияет.

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

P.S. очередная провокация?[/QUOTE]
сей пост есть чистейший гон, как и другие подробности С++. все кто не верит рекомендую проверить следующий код
Код:
void func( const char* string )
{
    char* string2 = (char*)string;

    string2[0] = 'b';
}

int _tmain(int argc, _TCHAR* argv[])
{
    char string[0x20] = "a";

    func( string );

   
    return 0;
}
3
26 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=Svyatozar]Научи-ка меня оптимизировать код :D
[/QUOTE]
Хорошо. Что именно тебя интересует?

Оптимизация - процесс улучшения системы по конкретному критерию. Так что для начала надо определиться с критерием оптимальности.

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

Что именно тебя интересует в самом процессе оптимизации?
Я готов тебя научить, тому что знаю сам.

[QUOTE=Svyatozar]
Твоя уверенность в оптимальности максимального разбивания на функции напоминает мне такой случай.
[/QUOTE]
Не "максимальности", а логичности и законченности каждой функции.
В идеале функция должна быть как маленький кирпичик, делающая только то, что вытекает из её названия, получая на вход минимальное количество связанных аргументов и выдающая на выходе конкретное значение, зависящее от этих аргументов.

Твоя уверенность мне тоже многое напоминает, поэтому и пытаюсь показать, как все же правильнее.
3
26 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=PitxBull]сей пост есть чистейший гон, как и другие подробности С++. все кто не верит рекомендую проверить следующий код
Код:
void func( const char* string )
{
    char* string2 = (char*)string;

    string2[0] = 'b';
}

int _tmain(int argc, _TCHAR* argv[])
{
    char string[0x20] = "a";

    func( string );

   
    return 0;
}
[/QUOTE]
Это типичная ошибка новичков.
Ты слышал что-нибудь о 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
351
26 сентября 2006 года
PitxBull
633 / / 22.12.2004
[QUOTE=aks]А у константного объекта (скажем переданного в другой метод описанным выше способом) можно вызывать только константные методы типа такого:
 
Код:
void getname() const;

Но естественно константный метод не имеет права менять данные класса.
Так что все таки это хороший тон описывать любой публичный метод не меняющий содержимое класса как константный. Ведь было бы странно еслиб у константного объекта мы не могли вызвать метод getName();[/QUOTE]
еще один гон - я спокойно могу написать в методе void getname() const; код изменяющий состояние объекта - по той простой причине что у компилятора нет способа проверить изменяет мой код объект или нет. он конечно может делать это в случае простых перемменых ( int, char ) но если один объект агрегирует в себе другой - и я перегрузил например оператор присваивания - компилятор никак не может проверить изменил я объект или нет.... гыг .... потом проверю это утверждение на пркатике но боюяся что и в этом случае я прав. таким образом const-модификатор функции - полная лажа... а один beep-менеджер меня из за незнания такой фигни на работу не взял.... мол const - єто супер важная примочка .... гыг гыг .... чисто декоративный элемент.... когда же этих beep-менеджеров супер-преподов начнут мочить в сортирах ?
3
26 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=PitxBull]еще один гон - я спокойно могу написать в методе void getname() const; код изменяющий состояние объекта - по той простой причине что у компилятора нет способа проверить изменяет мой код объект или нет. он конечно может делать это в случае простых перемменых ( int, char ) но если один объект агрегирует в себе другой - и я перегрузил например оператор присваивания - компилятор никак не может проверить изменил я объект или нет.... гыг .... потом проверю это утверждение на пркатике но боюяся что и в этом случае я прав. таким образом const-модификатор функции - полная лажа... а один beep-менеджер меня из за незнания такой фигни на работу не взял.... мол const - єто супер важная примочка .... гыг гыг .... чисто декоративный элемент.... когда же этих beep-менеджеров супер-преподов начнут мочить в сортирах ?[/QUOTE]
Перед тем, как что-либо так категорично и так эмоционально утверждать, для начала надо действительно всеже проверять.
Ты будешь удивлен возможностями компилятора.
А он действмтельно проверит изменения и сделает это довольно просто: вызываемые методы всех агрегированных объектов должны быть так же константными. :)

P.S. соболезную твоим неудачам в трудоустройстве, но менеджера понимаю.
351
26 сентября 2006 года
PitxBull
633 / / 22.12.2004
[QUOTE=Green]Это типичная ошибка новичков.
Ты слышал что-нибудь о 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]
ты ясно написал что нельзя - а я ясно показал что можно - за что удалено было это сообщение ?
351
26 сентября 2006 года
PitxBull
633 / / 22.12.2004
[QUOTE=Green]Перед тем, как что-либо так категорично и так эмоционально утверждать, для начала надо действительно всеже проверять.
Ты будешь удивлен возможностями компилятора.
А он действмтельно проверит изменения и сделает это довольно просто: вызываемые методы всех агрегированных объектов должны быть так же константными. :)

P.S. соболезную твоим неудачам в трудоустройстве, но менеджера понимаю.[/QUOTE]
гыг смотрим код ниже и делаем вывод что Green, как и тот некомпентный менеджер просто пара новичков
Код:
class B
{
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;
};
309
26 сентября 2006 года
el scorpio
1.1K / / 19.09.2006
[QUOTE=Pitxbull]char* b = (char*)a;
b[0] = 'f';
[/QUOTE]
Производится переопределение "указателя на константу" как "указатель на переменную". Операция возможная, как проезд на красный цвет, и настолько же чреватая "последствиями"
А использовать char* :confused: в программах, особенно в "примерах" не стоит - об этот тип изрядно зубы обламывали люди и поопытнее Вас :(

P.S. Кстати, а что означает код "return (int)b.Get_a();" :eek: ?
5.4K
26 сентября 2006 года
Svyatozar
221 / / 11.09.2006
[QUOTE=el scorpio]P.S. Кстати, а что означает код "return (int)b.Get_a();" :eek: ?[/QUOTE]
Это означает вернуть числовое значение адреса строки, возвращаемое функцией B::Get_a().
5.4K
26 сентября 2006 года
Svyatozar
221 / / 11.09.2006
Господа, для 64-битной совместимости обязательно используйте long для хранения адресов:

Код:
#include <stdio.h>

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'
309
26 сентября 2006 года
el scorpio
1.1K / / 19.09.2006
Цитата:
Это означает вернуть числовое значение адреса строки, возвращаемое функцией B::Get_a()


Зачем? Если требуется узнать адрес символьного массива (для отладки), достаточно привести его к void*. Всё остальное - от лукавого.

Цитата:
7fff8368e710 inside B constructor: 'a'
7fff8368e710 inside B::Get_a() const: a or f? 'f'
7fff8368e710 char * returned to main(): 'f'


Всё правильно. Оператор const означает, что объект, на который указывает указатель, невозможно изменить, используя этот указатель.
Да, указатель на константный объект можно переопределить как указатель на переменную - собственно говоря, любой указатель можно переопределить как что угодно :( - компилятор это разрешает. Вернее, компилятор "умывает руки", позволяя пользователю всю оставшуюся жизнь отлавливать runtime errors.

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

Ну а на работу подобного "специалиста" я бы тоже брать не стал :D

351
26 сентября 2006 года
PitxBull
633 / / 22.12.2004
[QUOTE=el scorpio]Производится переопределение "указателя на константу" как "указатель на переменную". Операция возможная, как проезд на красный цвет, и настолько же чреватая "последствиями"
А использовать char* :confused: в программах, особенно в "примерах" не стоит - об этот тип изрядно зубы обламывали люди и поопытнее Вас :(

P.S. Кстати, а что означает код "return (int)b.Get_a();" :eek: ?[/QUOTE]
я всего лишь хотел показать const вовсе не гарантирует неизменность объекта, злонамеренный код вроде того который привел я спокойно может изменить его, таким образом const - всего лишь декоративный элемент и ровным счетом ничего не гарантирует. такисм образом слова "многоопытных" Green и aks - как и соответсвующая выдержка из учебников по C++ - чистейший гон. ну и кто из нас более опытный ? :D
3.0K
26 сентября 2006 года
Мerlin
267 / / 25.07.2006
В pascale нет const, в Visual Basic тоже нет, в VBA... Вобщем проще сказать, что этот const имеется только в С++ и возможно в java. Но на других языках спокойно пишут сложные программы без этой "фичи". А вот некоторые С++ программисты шаг не могут сделать без этого костыля. Почему? На всех остальных языках программируют одни гиганты мысли, а программистами на С++ идут только те кадры, которым и HTML не позубам?
351
26 сентября 2006 года
PitxBull
633 / / 22.12.2004
[QUOTE=el scorpio]Зачем? Если требуется узнать адрес символьного массива (для отладки), достаточно привести его к void*. Всё остальное - от лукавого.[/QUOTE]
гыг ... вот интересно зачем приводить его к void* если спокойно можно узнать его адрес и без этого ?

[QUOTE=el scorpio]
Всё правильно. Оператор const означает, что объект, на который указывает указатель, невозможно изменить, используя этот указатель.
Да, указатель на константный объект можно переопределить как указатель на переменную - собственно говоря, любой указатель можно переопределить как что угодно :( - компилятор это разрешает. Вернее, компилятор "умывает руки", позволяя пользователю всю оставшуюся жизнь отлавливать runtime errors.

const означает, что программист даёт слово, что переданный объект изменяться во время выполнения функции не станет. Если же программист не только переопределяет указатель на константу, но и изменяет этот объект :eek: - тогда его обычно очень больно бьют :( , чтоб впредь подобными безобразиями не страдал.[/QUOTE]
таким образом оператор const с практически равным эффектом может быть заменен соответсвующим комментарием, что указывает на то что он абсолютно не является необходимым. я бы бил beep-менеджеров которым не дано этого понять до тех пор пока они бы не дали обещание больше никогда не заниматься программированием и не портить другим гораздо более одаренным людям жизнь.
[QUOTE=el scorpio]
Ну а на работу подобного "специалиста" я бы тоже брать не стал :D[/QUOTE]
ты предсталяешь я бы тя на работу тоже не взял, даже если б твою зарплату платили мне а не тебе.
10
26 сентября 2006 года
Freeman
3.2K / / 06.03.2004
Мнения по проблеме выяснены, [COLOR="Red"]тема закрыта[/COLOR].
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог