Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Вопрос из книги Страуструпа


Автор: shuttle 17.6.2009, 12:13
Как понимать следующее описание? Где оно может пригодиться?

Код

typedef int (rifii&) (int, int);


Что то не могу ссобразить.

Автор: xvr 17.6.2009, 12:30
Референс на функцию, принимающую 2 параметра (оба int) и возвращающую int.
Цитата

Где оно может пригодиться?
Это надо спрашивать у того, кто это написал  smile 

Автор: shuttle 17.6.2009, 12:34
это Страуструп написал в книге "Язык программирования С++". Очень кстати толковая книга.

Автор: kemiisto 17.6.2009, 12:37
Цитата(shuttle @  17.6.2009,  10:34 Найти цитируемый пост)
Очень кстати толковая книга. 

Это видно потому, что Вы спрашиваете. smile То есть конструкция есть, а зачем, где и как её пользовать =  нема. Очень толковая книга. smile  

Автор: zim22 17.6.2009, 12:51
Цитата(shuttle @  17.6.2009,  12:13 Найти цитируемый пост)
Как понимать следующее описание?

у меня оно вообще не компилится.
http://codepad.org/t9HY5Sqr

может быть имелся ввиду указетель на функцию?
Код

typedef int (*rifii) (int, int);

Цитата(shuttle @  17.6.2009,  12:34 Найти цитируемый пост)
это Страуструп написал

какая страница? какое издание книги?

Автор: shuttle 17.6.2009, 13:09
Бьерн Страуструп.
Язык программирования С++
Второе дополненное издание
Языки программирования / С++

там еще на обложке морская волна. страница 120. упражнение 2.

Автор: zim22 17.6.2009, 13:15
Цитата(shuttle @  17.6.2009,  13:09 Найти цитируемый пост)
Второе дополненное издание

у меня другая книжка smile не исключено, что у вас очепятка всего навсего.
"Специальное издание"
isbn 5-7989-0223-4
***
у меня на стр.120 вообще нет упражнений. 

Автор: shuttle 17.6.2009, 13:29
Все разобрался, сравнил с "Язык программирования С++ специальное издание", у меня точно опечатка 
должно быть так 
Код

typedef int (&rifii) (int, int);

а не 
Код

typedef int (rifii&) (int, int);


В "Язык программирования С++ специальное издание" это 206 страница.

Автор: zim22 17.6.2009, 13:38
для чего это может пригодиться... для этого: smile
Код

typedef int (&rifii) (int, int);

int fcn(int,int) {return 5; }

int fcn2(rifii rf) { return 10; }
int main () {
  rifii r = fcn;
  r(10,20);

  fcn2(r);
}

***
плохой пример я привёл... исправляюсь
Код

typedef int (&rifii) (int, int);

int print(int i, int j) {
  cout << i << " " << j;
  return 0;
}
int formatted_print(int i, int j) {
  cout << "I: " << i << " J: " << j << endl;
  return 1;
}
void calculate(rifii r) {  
  r(10, 20);
}

int main () {
  calculate(print);
  calculate(formatted_print);
}

Автор: andrew_121 17.6.2009, 13:45
А в чем разница между указателем на функцию и ссылкой?

Автор: mes 17.6.2009, 13:47
Цитата(andrew_121 @  17.6.2009,  12:45 Найти цитируемый пост)
А в чем разница между указателем на функцию и ссылкой? 

в том, что ссылка должна быть изначально инициализирована.
 

Автор: zim22 17.6.2009, 13:47
Цитата(andrew_121 @  17.6.2009,  13:45 Найти цитируемый пост)
А в чем разница между указателем на функцию и ссылкой?

наверное в том же, в чём разница между передачей аргументов по указателю и ссылке smile

Автор: mes 17.6.2009, 13:48
Цитата(zim22 @  17.6.2009,  12:47 Найти цитируемый пост)
наверное в том же, в чём разница между передачей аргументов по указателю и ссылке smile 

не совсем.. функция в отличии от объекта не может быть временной smile

Автор: andrew_121 17.6.2009, 13:50
Цитата(mes @  17.6.2009,  13:47 Найти цитируемый пост)
в том, что ссылка должна быть изначально инициализирована.

Походу, это единственный смысл.



Цитата(zim22 @  17.6.2009,  13:47 Найти цитируемый пост)
наверное в том же, в чём разница между передачей аргументов по указателю и ссылке

Это разные случаи.

Автор: mes 17.6.2009, 14:37
чего то захотелось вспомнить молодость и написать простой калькулятор, заодно демонстрация по теме :
Код

#include <iostream>

int plus  (int a, int b) { return a+b; }
int minus (int a, int b) { return a-b; }
int imul  (int a, int b) { return a*b; }
int idiv  (int a, int b) { return a/b; }

typedef int (&op_t) (int, int);

struct op_meta_t
{
    unsigned char key;
    std::string name;
    op_t operation;
};
op_meta_t op_meta_arr[] = { {'+', "plus", plus },
                            {'-', "minus", minus },
                            {'*', "imul", imul },
                            {'/', "idiv", idiv }
                          };
const unsigned op_meta_arr_size = sizeof (op_meta_arr)/ sizeof(*op_meta_arr);

void calculate (unsigned char key, int a1, int a2)
{
    for (unsigned i=0; i<op_meta_arr_size; ++i)
     if (op_meta_arr[i].key == key)
     {
         std::cout << a1 << " " << op_meta_arr[i].name << " " << a2 << " = " << op_meta_arr[i].operation(a1, a2)<<std::endl;
         return;
     }
   //-else-
     std::cout << "ERROR : operation not found"<< std::endl;
}

int main ()
{
    unsigned char op;
    std::cout << " operation :"; std::cin>>op;
    int a1, a2;
    std::cout << " argument 1 :"; std::cin>>a1;
    std::cout << " argument 2 :"; std::cin>>a2;

   calculate (op, a1, a2);

}



Автор: zim22 17.6.2009, 15:11
Цитата(mes @  17.6.2009,  14:37 Найти цитируемый пост)
чего то захотелось вспомнить молодость

видать в молодости вы тоже ошибки делали smile
попробуйте операцию умножить сделать.
***
в класс добавил конструктор. почему компилятор не ругается? ведь ссылка (op_t operation) должна быть инициализирована.
иначе при её вызове получим runtime error.
Код

struct op_meta_t
{
  op_meta_t() {}
    unsigned char key;
    std::string name;
    op_t operation;
};

***
в GCC ругается! а вот Студия молчит.

Автор: azesmcar 17.6.2009, 15:32
Цитата(zim22 @  17.6.2009,  15:11 Найти цитируемый пост)
в GCC ругается! а вот Студия молчит.

очередная ошибка студии...

Автор: mes 17.6.2009, 15:37
Цитата(zim22 @  17.6.2009,  14:11 Найти цитируемый пост)
видать в молодости вы тоже ошибки делали smile
попробуйте операцию умножить сделать.

ага .. как же без них..  else лишнее.. по запарке добавил smile 

Автор: azesmcar 17.6.2009, 15:37
Цитата

There shall be no references to references, no arrays of references, and no pointers to references. The declaration
of a reference shall contain an initializer (8.5.3) except when the declaration contains an explicit
extern specifier (7.1.1), is a class member (9.2) declaration within a class declaration, or is the declaration
of a parameter or a return type (8.3.5); see 3.1. A reference shall be initialized to refer to a valid object
or function.

Код

typedef int (&op_t) (int, int);

struct v
{
    op_t t;
};

int main ()
{
    v q;
    q.t(1, 2);
}

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

Добавлено через 1 минуту и 14 секунд
если заменить на int& - орет нечеловеческим голосом, а вот с функциями - молчит как партизан smile 

Автор: andrew_121 17.6.2009, 16:08
azesmcar, Какой компилятор?

Автор: azesmcar 17.6.2009, 16:09
Цитата(andrew_121 @  17.6.2009,  16:08 Найти цитируемый пост)
azesmcar, Какой компилятор? 

VS2008 Professional

Автор: andrew_121 17.6.2009, 22:28
Я так и думал. Жаль не могу сам проверить сей факт.

Автор: zim22 18.6.2009, 18:18
думаю сюда вопрос напишу, т.к. это вопрос и он из книги Страуструпа smile
***
В книге написано, что:
Цитата

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

И приводится пример кода:
Код

class S;
S* h(S*);

void k(S* p) {
  S a; // ошибка: S не определён, а для выделения памяти требуется знать его размер
  S* q = h(p); // правильно - указатель можно передавать и разместить  
}

так вот, где "правильно" написано - оно не правильно. Линкер ругается на  unresolved external symbol
или Страуструп имел ввиду правильность с точки зрения компилятора, а не линкера?

Автор: mes 18.6.2009, 18:24
Цитата(zim22 @  18.6.2009,  17:18 Найти цитируемый пост)
так вот, где "правильно" написано - оно не правильно. Линкер ругается на  unresolved external symbol
или Страуструп имел ввиду правильность с точки зрения компилятора, а не линкера?

Имел ввиду что где то в дальнейшем тело функции будет написано. Но не написал, так как само тело не относится к обсуждаемому вопросу . smile

Цитата(zim22 @  18.6.2009,  17:18 Найти цитируемый пост)
Именем типа структуры можно пользоваться до определения типа, пока не требуется знания имен членов или размера структуры.

никаких ошибок связанных с этой цитатой в коде нет smile

Автор: EvilsInterrupt 11.10.2009, 00:50
У меня есть два вопроса относительно того, что поясняет в своей книге Страуструп.

Вопрос №1:
В 6.2 "Обзор операторов" на странице 163, он приводит код:
Код

int * pp = &(x > y ? x : y); // адрес целого с большим значением

и ниже текст:
Цитата

Если и второй, и третий операнды оператора ?: являются lvalue и имеют одинаковый тип, результат имеет тот же тип и является lvalue.


Не совсем понимаю, как может то что справа быть lvalue-ем ? Ведь lvalue это то куда присваивают значение?!

Вопрос №2:
Рядышком, на следующей 164 страничке в Главе 6. Выражения и инструкции. Есть код:
Код

int i = 1;
v[i] = i++; // результат не определен

и слова:
Код

может вычисляться либо как v[1] = 1 либо как v[2] = 1, либо привести к еще более странным странным результатам.

Не совсем понимаю эту "неопределенность" .  возникнуть чтото отличное от v[1] = 1; ? Хоть один компиллер назовите, который генерит такую вот неопределеность ?

Автор: GoldFinch 11.10.2009, 00:58
EvilsInterrupt, может произойти
Код

t=i;
v[i] = t;
++i;
а может
Код

t=i;
++i;
v[i] = t;


Добавлено через 1 минуту и 16 секунд
EvilsInterrupt, lvalue - Это то что может быть слева. это не запрещает ему при это быть и rvalue

Автор: EvilsInterrupt 11.10.2009, 01:09
GoldFinch, я привык видеть конкретный код! Назови плиз хоть один компиллер, который генерит подобное ?

Автор: mes 11.10.2009, 01:34
Цитата(EvilsInterrupt @  11.10.2009,  00:09 Найти цитируемый пост)
Назови плиз хоть один компиллер, который генерит подобное ? 

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

Цитата(EvilsInterrupt @  10.10.2009,  23:50 Найти цитируемый пост)
Не совсем понимаю, как может то что справа быть lvalue-ем ? Ведь lvalue это то куда присваивают значение?!

Код

int a = 4;
int b = 5;

(true? a : b)=15;
std::cout << a << " " << b << std:: endl;

(!true? a : b)=25;
std::cout << a << " " << b << std:: endl;

Автор: zim22 11.10.2009, 09:06
Цитата(EvilsInterrupt @  11.10.2009,  00:50 Найти цитируемый пост)
Не совсем понимаю, как может то что справа быть lvalue-ем ? Ведь lvalue это то куда присваивают значение?!

очень просто определить, является ли объект lvalue или rvalue
достаточно попробовать взять его адрес

Код

int x, y;   
(x + y) = 20; // rvalue, т.к. &(x + y) - ошибка компилятора
(x += y) = 20 ;// lvalue, т.к. &(x += y) - компилится успешно


Автор: EvilsInterrupt 11.10.2009, 13:29
Ладно, случай с компиллером оставлю до завтра, когда самплов на генерю наработе. 
А вот вопрос с lvalue хочется все-таки до понять.

Порывшись в поисковике увидел:
http://athena.vvsu.ru/carina/oop/link/cpps/ref_3.shtml.htm сказано, также как считаю и я:
Цитата

Объект есть область памяти; lvalue (адрес) есть выражение, ссылающееся на объект. Очевидный пример адресного выражения - имя объекта. Есть операции, дающие адресные выражения: например, если Е - выражение типа указатель, то *Е - адресное выражение, ссылающееся на объект, на который указывает Е. Термин "lvalue" происходит из выражения присваивания Е1=Е2, в котором левый операнд Е1 должен быть адресным (value) выражением.


есть
Код

int * p = &(x>y ? x : y);


это можно раскрыть в:

Код

if ( x > y ) 
{
   p = &x;
}
else
{
   p = &y;
}


тута вижу только p ,как lvalue . Потому что &x, &y стоят справа! Поэтому мне и не понятно, почему это Страуструп объект стоящий справа, а не слева называет lvalue ?!

P.S.:
Пока ктото напишет мне могу взорваться от непонимания и потому пока почитаю http://www.rsdn.ru/article/cpp/lvalue.xml )))

Автор: mes 11.10.2009, 13:55
Цитата(EvilsInterrupt @  11.10.2009,  12:29 Найти цитируемый пост)
Поэтому мне и не понятно, почему это Страуструп объект стоящий справа, а не слева называет lvalue ?!

lvalue не обязательно должен стоять физически слева.
например int а, b; a = b;  // а и b lvalue несмотря на то что одно стоит слева другое справа.
если точнее, то  в данном примере справа в роли rvalue выступает lvalue b;
подобно как например в русском языке имя прилагательное может переходить в разряд имен существительных :
больной (прил) человек  и  больной (сущ).
так и в программировании выражение одной сути может исполнять роль другой.

Автор: EvilsInterrupt 11.10.2009, 14:11
Кажется начал понимать, прошу проверить ход мыслей до вывода ;)

Ввиду того что с любым выражением как-то должно связано либо адрес со значением по этому адресу, либо просто значение. То хочется различать просто значение от значения по адресу, поэтому и обозначили значение лежащее по адресу как lvalue. Наскоко понял из статьи что у меня в P.S.: из прошлого поста, то первоначально это и обозначало объект стоящий слева от присваивания, а сейчас компиллеры стали круче и потому уже не актуально )
Из той же статьи, что в P.S.:
Цитата

char a [10];

i      —   lvalue
++i    —   lvalue
*&i    —   lvalue
a[5]   —   lvalue
a[i]   —   lvalue

однако:

10     —   rvalue
i + 1  —   rvalue
i++    —   rvalue


не понятно, почему последнее i++ написано rvalue ? Попробую представить как i += 1 и вроде как понятно, что такое не может быть lvalue , т.е. в такое мы не можем кинуть значение, но почему тогда ++i является lvalue ? ведь посути это можно писать как result = (i+=1,i); в такое тоже сложно представить чтобы чтото писать ?! ;)

Автор: mes 11.10.2009, 14:19
Цитата(EvilsInterrupt @  11.10.2009,  13:11 Найти цитируемый пост)
но почему тогда ++i является lvalue ?

потому что возвращают разное :
Код

int post_increment(int & i)
{
   int old =  i;
   i+=1;
   return old; // возвращает временное значение
}

int & prefix_increment (int & i)
{  
   i+=1;
   return i; // возвращает оригинал по ссылке
}

Автор: mes 11.10.2009, 14:58
Цитата(EvilsInterrupt @  11.10.2009,  13:11 Найти цитируемый пост)
а сейчас компиллеры стали круче и потому уже не актуально )

при чем тут мощность компиляторов я не понял smile

Автор: EvilsInterrupt 11.10.2009, 15:18
mes, ну к тому, что раньше lvalue применялось исключительно к объектам слева от присваивания и только им ;) Так по крайней мере баит дядя Бьярни )

Автор: mes 11.10.2009, 15:44
Цитата(EvilsInterrupt @  11.10.2009,  14:18 Найти цитируемый пост)
ну к тому, что раньше lvalue применялось исключительно к объектам слева от присваивания и только им ;)

это  с мощностью компилятора никак не связано...smile

Автор: xvr 11.10.2009, 19:59
lvalue это не то, что СТОИТ слева от оператора присваивания, а то, что МОЖЕТ стоять слева, т.е. то, чему можно присвоить. Это так же означает, что у этих объектов можно взять адрес, т.е. они представляют некую сущность, существующую не только в процессе вычисления выражения.
Тут int * p = &(x>y ? x : y); x и y представляют собой такие сущности (это переменные), у них можно взять адрес и им можно присвоить. Т.е. результат всего оператора ? будет являться lvalue, и от него можно взять адрес.
Если же мы рассмотрим такое выражение int * p = &(x>y ? x+y : y);, то x+y не является lvalue, т.к. это значение существует только внутри выражения, и недоступно как отдельный объект. У него нет адреса, который можно было бы взять, и оператор ? не будет lvalue.

Заметим, что если бы x и y были объектами для которых был бы перегружен оператор +, как возвращающий lvalue (например ссылку), то оператор ? снова стал бы lvalue (за что С++ иногда и критикуют  smile )


Автор: stat007 11.10.2009, 21:53
shuttle, Лучше читай Страуструпа - 3-е издание... Там всё более понятнее...

Автор: bsa 12.10.2009, 10:21
Лучше Страуструпа вообще не читать, пока не станешь разбираться в С++. Сначала надо изучить С++, затем прочитать Мейерса и Александреску, а потом уже можно и за "Страуса" браться...

Автор: zim22 12.10.2009, 10:36
Цитата(bsa @  12.10.2009,  10:21 Найти цитируемый пост)
+, затем прочитать Мейерса и Александреску, а потом уже можно и за "Страуса" браться...

bsa, не соглашусь. я сейчас читаю Страуструпа - ничего там сложного нет. главное - вдумчиво читать smile
(Страуструп - это моя вторая книга по С++. Первую прочитал Стенли Липпман "Язык программирования С++. Вводный курс. 4 издание")
Александреску гораздо сложней для понимания.

Автор: bsa 12.10.2009, 10:58
zim22, это не мое мнение. Но знающие люди утверждают, что страус может сбить с пути истинного неокрепший ум новичка. Поэтому прежде чем его читать, нужно знать, что есть хорошо, а что плохо.

Автор: zim22 15.10.2009, 19:25
Сегодня натолкнулся на один абзац текста, правдивость которого поставил под сомнения.
Действительно ли в нижеприведённом коде преобразования типов не разрешаются?

Код

template <class C>
int get_nth(C &p, int n); // получение n-го элемента

Цитата

Предположительно эта функция возвращает значение n-го элемента контейнера типа C. Т.к. С должен быть выведен по фактическому аргументу в вызове get_nth(), преобразования типов для первого аргумента не разрешаются. Однако второй аргумент является совершенно обычным, поэтому рассматривается полный диапазон возможных преобразований. Например:

Код

class Index {
public:
  operator int();
};

void f(vector<int> &v, short s, Index i) {
  int i1 = get_nth<int>(v, 2); // точное совпадение
  int i2 = get_nth<int>(v, s); // стандартное преобразование short в int
  int i1 = get_nth<int>(v, i); // преобразование Index в int, определяемое пользователем
}

***
zim22: Но если немножко изменить функции, то будет вызвано преобразование из Index в int для первого аргумента функции.
Код

template <class C>
int get_nth(const C &p, int n); 

void f(short s, Index i) {
  int i1 = get_nth<int>(i, s); // вызывается функция с аргументами (const int&, int)
}

Автор: bsa 18.10.2009, 18:43
zim22, вот тебе и ответ, почему новичкам читать его не следует.

Автор: zim22 19.10.2009, 16:41
прочитав ещё пару страниц - снова споткнулся на непонятную мне ошибку. отложу Страуструпа до лучших времён smile

Автор: EvilsInterrupt 11.12.2009, 21:44
Возник вопрос, прошу пояснить ;) 
Есть код из книги Страуструпа:

Код

map<string, int> histogram;

void record(const string & s)
{
  histogram[s]++;
}


Мне непонятно что именно инкрементируется ?

Предположения:
1)
Тот int что был указан в создании гистограммы и строку поместили в мап и ассоциированный с нею инт инкрементируется ?
2)
Каждому объекту не явно задается какой-то инт и его можно инкрементировать ?

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

ЗЫ:
сорри, в сорцах заблудился и пока знаний маловато чтобы подобного рода вещи узнавать )

Автор: Abyx 11.12.2009, 21:54
EvilsInterrupt, очевидно инкрементируется int который в карте
какбэ эта карта состоит из int 
и фактически код представляет собой
Код

int histogram[];

void record(const string & s)
{
  histogram[ string_to_index(s) ]++;
}

Автор: EvilsInterrupt 11.12.2009, 21:55
Abyx, 
Спасибо ) А доп. вопрос ? ;)

Автор: Abyx 11.12.2009, 21:57
Цитата(EvilsInterrupt @  11.12.2009,  21:44 Найти цитируемый пост)
при создании в мапе создается исключительно один инт и одна стринг, или в довесок еще доп. инт, так сказать служебный куда помещается хэш или еще чтото в этом роде 

в map хешей нет, там бинарный поиск по упорядоченным ключам
т.е. если ключи - string, пары сортируются в алфавитном порядке

Автор: EvilsInterrupt 11.12.2009, 21:57
Abyx, Огромное спасибо.

Автор: Abyx 11.12.2009, 21:59
для хешей надо другой контейнер, boost::unordered_map, он же std::tr1::unordered_map
http://www.boost.org/doc/libs/1_41_0/doc/html/unordered.html

Автор: wedens 11.12.2009, 22:30
дабы не создавать новую тему, спрошу здесь.
как как калькулятор из книги находит имя переменной и возвращает её значение?
Код

    case Lexer::NAME:
            {
                            double& v = table[Lexer::pSym->string_value];
                            if(get_token() == Lexer::ASSIGN) v = expr(true);
                            return v;
            }

здесь я так понимаю в v возвращается значение, если в map существует запись string_value, а если не существует, то создается. но как тогда в эту запись приписывается double значение? 

Автор: xvr 11.12.2009, 22:56
Цитата(EvilsInterrupt @ 11.12.2009,  21:44)
Возник вопрос, прошу пояснить ;) 
Есть код из книги Страуструпа:

Код

map<string, int> histogram;

void record(const string & s)
{
  histogram[s]++;
}


Мне непонятно что именно инкрементируется ?

Рассмотрим, что тут написано (вот это histogram[s]++;):
Код

int &value = histogram. operator[] (s);
value++;
Здесь operator[] - это обычная функция класса map, возвращающая ссылку на int. Она работает так: если в map есть строка, заданная параметром, то возвращается ссылка на поле данных (int). Если же такой строки нет, то она добавляется в map, для поля данных используется конструктор без параметров, т.е. int() - что обозначает инициализацию 0 (для POD типов данных). Ссылка на вновь добавленное поле возвращается.
Затем инкрементируется значение по возвращенной ссылке.

Цитата

попутный доп. вопрос:
при создании в мапе создается исключительно один инт и одна стринг, или в довесок еще доп. инт, так сказать служебный куда помещается хэш или еще чтото в этом роде ?
Снаружи видно только строку и int, все остальное - внутреннее дело map'а (там еще как минимум 3 поля для организации B/R дерева)

Автор: Леопольд 13.12.2009, 21:10
Цитата(wedens @  11.12.2009,  22:30 Найти цитируемый пост)
как калькулятор из книги находит имя переменной и возвращает её значение?

Помню тоже долго разбирался в нём. Я считаю что это пример отвратителен с точки зрения поддержки и расширения. Возможно я ошибаюсь, не спец в проектировании, но на мой взгляд, код безоговорочно должен быть простым для понимания, частенько в этом помогают комментарии, но самое главное, надо реализовать алгоритм, понятный для человека - дерево синтаксического разбора разбивает выражение по приоритетам, потом всё выражение вычисляется и т.д. 
А у Страуструпа, насколько помню, три функции рекурсивно вызывают друг друга в зависимости от нескольких ифоф, и создают приличную "мешанину" в стеке вызовов, которую тяжело проследить. При этом всё жестко завязано с парсером, брр... У него изначально функциональность разделена на части неправильно. Жаль что он не написал перед началом примера
Внимание! Плохой стиль. Ни в коем случае не пытайтесь повторить! smile

Автор: EvilsInterrupt 13.12.2009, 23:33
Леопольд, 
Буквально месяца 2-3 назад читал код калькулятора Страуструпа и понял его буквально  за 30 мин. Сейчас смотрю и думаю чего там сложного-то ? Что собственно произошло за это время? По своим антивирусным задачам, дома(если шеф увидит smile, начал писать мини-оптимизатор машинного кода, для этого начал читать про компиллеры от Ахо и его мысли про создание промеж. языка и оптимизации в нем. Видимо это и дало столь быстрое понимание калькулятора Страуструпа.

Думаю Бьярн, как и многие люди поступил как обычный человек: "Мне же понятно, вот же есть грамматика, вот есть код. Возьму элементарнейший калькулятор, каких еще поискать", но он забывает, что по его книге могут учиться совсем ньюбы! А возможно и не забывает, а сделал допущение что читают уже серьезные люди когда-то программившие на си и теперь изучающие плюсы.

Мое личное мнение по поводу книги, Страуструп предположил, что язык вышел излишне сложным и поэтому пишет даже в начале : "Если вы чтото не поняли, не переживайте и идите дальше. В дальнейших главах будем говорить более детально". Также думаю, что он писал книгу прежде всего для программистов на языке Си. Это учитывая тот факт, когда она появилась впервые и какую цель он преследовал создавая язык, какие сложности вставали до его языка. А дальше просто ее саппортил ;) Вот и вышло, старые грабли, получили новую жизнь !


Вывод:
Читать, читать, но читать много проходно! Как компиллер проходит по сорцу! Сначала токены, потом лексемы, потом грамматика и т.д. и т.п. ;)
 

Автор: EvilsInterrupt 14.12.2009, 08:58
Читаю про enum-ы ;)

вот, что пишет:
"Диапазон значений перечисления определяется след. образом. Пусть n-максимальное возможное значение элемента перечисления . Пусть m-такое минимальное целое, что 2^m-1 больше или равно n. Тогда верхняя граница диапазона равна 2^m-1. Если наименьший элемент имеет неотрицательное значение, нижняя граница диапазона равняется нулю. Если наименьшее значение отрицательно,  нижней границей диапазона является наименьшая ближайлая отрицательная степень двойки плюс 1. Таким образом, диапазон определяется минимальным количеством бит требуемым для представления значений всех элементов перечисления"

из этого следует, что автор сделал допущение в сторону мало-мальски математематически подкованного читателя!

Автор: Леопольд 14.12.2009, 13:35
Цитата(EvilsInterrupt @  13.12.2009,  23:33 Найти цитируемый пост)
Буквально месяца 2-3 назад читал код калькулятора Страуструпа и понял его буквально  за 30 мин. 

Думаю, мне бы сечас тоже особого труда не составило, потому что я сейчас работаю на языке, где goto использутеся буквально через каждые 10 строк кода. Точнее поддерживаю этот бред. smile

А так как книга Страуструпа была у меня второй, после Подбельского и мышление ещё не выработалось, я разбирался в "калькуляторе" около дня.

Автор: EvilsInterrupt 14.12.2009, 14:27
Леопольд, готу рулит! ;))) я сам ща в таком коде плаваю из-за рабочей задачи поставленной партией ;) мало того что это гоуту, так еще коду 10 лет и писало его столько же же чел, каждый возвращался в разные промежутки временного отрезка год, два . А люди как правило за годы "умнеют" и написание кода тоже меняется. Это не есть хорошу(первоначальный вариант этого сообщения было грубее, сорри)

Автор: Леопольд 14.12.2009, 15:14
Цитата(EvilsInterrupt @  14.12.2009,  14:27 Найти цитируемый пост)
так еще коду 10 лет

Хех, "моему" коду не менее 20 лет. И писало его человек надцать, если не больше. Вся система состоит из 1000 - 1500 файлов по 15000-70000 строк кода (вместе с комментами). Никто её не знает целиком, только небольшую её часть. Это добро, примерно на 70% задокументированно, но качество документации хромает на все конечности smile

Автор: EvilsInterrupt 14.12.2009, 20:56
Леопольд,  Будут мысли хорошего и эффективного рефакторинга кода с goto пиши! ;) Только плиз в виде отдельной темы, все равно понадобиться. Хотя бы нам двоим хранить мысли по войне с готу )

Автор: bsa 14.12.2009, 21:24
Цитата(EvilsInterrupt @  14.12.2009,  20:56 Найти цитируемый пост)
Будут мысли хорошего и эффективного рефакторинга кода с goto пиши!
Поищи в религиозных войнах. Я использую следующие способы:
1. разделение на функции (return лучше, чем goto)
2. выделение части кода в цикл do { }while (false);
3. исключения, но это в редких случаях (когда речь идет об обработке редких ошибок).

Автор: EvilsInterrupt 14.12.2009, 21:39
bsa, бросание исключений не допустимо! код нужен максимально быстрым! по поводу return и создание циклов согласен. Но я пока некоторые куски кода выделяю в новые методы и их дергаю, а их уж мне проще править )

Автор: djamshud 14.12.2009, 21:42
EvilsInterrupt, а зачем рефакторить goto, если оно к месту? Обрабатывать ошибки с ним можно красиво и понятно. Выходить из множества циклов тоже - единственное вменяемое решение. Если же речь идет про код, сплошь утыканный такого рода  переходами, то и рефакторинг не поможет - если не нравится, нужно просто переписывать плохие места.

>1. разделение на функции (return лучше, чем goto)

Если только goto изначально используется в качестве вызова части кода, аля функции. Но это уже клиника, и разработчик нуждается в лоботомии.

>2. выделение части кода в цикл do { }while (false);

Шикарнейший костыль. Что люди только не делают, лишь бы не использовать правильный гоуту.

Автор: bsa 15.12.2009, 11:41
Цитата(djamshud @  14.12.2009,  21:42 Найти цитируемый пост)
Если только goto изначально используется в качестве вызова части кода, аля функции.

Ну не скажи:
Код
int func()
{
   if (...)
      goto end;
   ...
   if (...)
      goto end;
   <code1>
end:
   <code2>
}
можно переписать так:
Код
bool func1()
{
   if (...)
      return false;
   ...
   if (...)
      return false;
   return true;
}
int func()
{
   if (!func1())
     <code1>
   <code2>
}

Цитата(djamshud @  14.12.2009,  21:42 Найти цитируемый пост)
Шикарнейший костыль.
Угу, а кто спорит?


Модератор: Давайте вернёмся к теме обсуждения.

Автор: Леопольд 15.12.2009, 11:48
Цитата(EvilsInterrupt @  14.12.2009,  20:56 Найти цитируемый пост)
Леопольд,  Будут мысли хорошего и эффективного рефакторинга кода с goto пиши!

Не, не будут. Я не на плюсах работаю :( Так называемый PLEX. Хуж того. На PLEX'е я пишу тлько для того, что-бы этот дело, вручную перегнать в ASA - местный ассемблер.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)