LINUX.ORG.RU

Рекурсия

 ,


0

2

Привет. Вопрос по поводу организации проекта. По мере его роста возникает вопрос - как избегать рекурсию если захотелось дописать/переписать какую-то функцию (если я пишу новую функцию, то её, естественно, пока ещё никто не использовал). Мне видится два варианта:
1. cc/hh образуют единую единицу, которая может ссылаться на нижележащие единицы, ссылка на верх запрещена. Я даже спец утилиту написал, довольно неплохо вышло, строит иерархию, показывает обратные зависимости каждой единицы.
2. забить на иерархию. Если добавляю в тело ссылку на что-то из проекта, то меняею имя функции и смотрю на ошибки компиляции (отсутствие упоминания новоиспользованной части проекта). Различные run time проверки с той же серии.

Не знаю, позволило ли моё косноязычие донести смысл. Как вы поступаете в реальных проектах (сложней одномодульного hello world)? Сидеть ждать переполнения стека и пол дня копать под отладчиком?

★★

как избегать рекурсию

У меня два вопроса. 1) Зачем ее избегаать? 2) Как ты вобще случайно ее получить можешь?

Dudraug ★★★★★
()
Ответ на: комментарий от Dudraug

Ну в многофайловом проекте разве сложно.

// 1.cc
void show() {...; say();}

// 10.cc
void say() {
...;
// Прошёл месяц с момента написания функции
// и мы решили добавить. Ну а чего, ведь
// удобно, когда и говорит, и показывает ))
  show();
}

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Действительно удобно. А в чём проблема? Это ведь не означает, что они будут друг друга копировать.

anonymous
()

используй обход дерева в ширину - алгоритм bfs.

SergikXP
()
Последнее исправление: SergikXP (всего исправлений: 1)
Ответ на: комментарий от pavlick

Это нужно совершенно выпасть из контекста архитектуры программы и не желать её восполнить в голове. Или спроектировать архитектуру изначально угрёбищно.

Deleted
()
Ответ на: комментарий от SergikXP

Кого ее? Случайно получить бесконечну рекурсию не так и просто, это надо совсем неадекватно код писать.

Ну и дебагером она ловится довольно быстро,а не по «пол дня» как думает ОП.

Dudraug ★★★★★
()
Ответ на: комментарий от Deleted

Ну держать всё в голове не удастся, к сожалению. Скелет программы в голове, а мелочовка не задерживается.

№ 2 не плох для си, для плюсов с его перегрузками не 100 процентный способ.

Кстати, для себя вопрос я решил, наверное. Совершенно забыл о всяких clang утилитах. В частности - rtags, умеет rtags-find-reference (находит все ссылки на символ), адекватно работает с плюсами с его перегрузками.

pavlick ★★
() автор топика

Сидеть ждать переполнения стека

Да.

Также в контексте запрета «ссылок наверх» напоминаю о такой полезной фиче языка, как указатели на функции.

Sorcerer ★★★★★
()
Ответ на: комментарий от Sorcerer

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

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Тестировать надо только что написанный код, вот и все. Таких нелепых казусов избежать можно только на 100% понимая что делаешь в каждый момент времени. Жаль, что к пограммистам такое человеческое кач-во не применимо.

Deleted
()

открыт ещё один способ выстрелить в ногу ?

прощай tailcall..

только программирование позволяет компенсировать недостаток ума деревянным костылём :-)

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

только программирование позволяет компенсировать недостаток ума деревянным костылём :-)

ты бы видел костыли инженерии... плакал бы кислотой

Deleted
()
Ответ на: комментарий от Deleted

ты бы видел костыли инженерии... плакал бы кислотой

если бы господь бог создавал мир как наши строители то первая муха вызвала бы конец света :-)

MKuznetsov ★★★★★
()

Если вы так боитесь рекурсии, то могу посоветовать перейти на Fortran IV или еще более древние диалекты, где действительно была запрещена взаимная рекурсия, но это скорее связано с архитектурой тогдашних компьютеров и операционных систем. Можете поинтересоваться на счет современных Фортранов. Некоторые утверждают, что они вполне ничего.

dave ★★★★★
()

Не знаю, позволило ли моё косноязычие донести смысл. Как вы поступаете в реальных проектах (сложней одномодульного hello world)? Сидеть ждать переполнения стека и пол дня копать под отладчиком?

Например, можно почитать книги по паттернам проектирования и дизайну приложений.

xpahos ★★★★★
()
Ответ на: комментарий от xpahos

Например, можно почитать книги по паттернам проектирования и дизайну приложений.

можно почитать наставления по военному делу. или справочник кровельщика..или Хеменгуея

а код надо писать блжатъ :-)

MKuznetsov ★★★★★
()
Последнее исправление: MKuznetsov (всего исправлений: 1)

Лол, никогда случайно не попадал в рекурсии. Даже таких историй не слышал.

anonymous
()

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

peregrine ★★★★★
()
Ответ на: комментарий от peregrine

Эмм. Если А требует Б, который требует А — в хедерах тупо «class N;», а в имплементации уже инклюды — это нормально?

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

Если у тебя есть ответ на вопрос, почему они это требуют и действительно ли это нужно, то норм. Но всё равно с этим бывают всякие лажи:

void f(B *);
void f(void *);
class A;
A *a;
f(a); // f(void *)
class A : B {};
f(a); // f(B *)
+ автор A не сможет заменить A на typedef шаблона или ещё что.

vzzo ★★★
()
Последнее исправление: vzzo (всего исправлений: 1)
Ответ на: комментарий от MKuznetsov

Написать такой код, который привел топикстартер, во вменяемом состоянии невозможно. Цель ООП как раз в том, чтобы каждый модуль являлся некоторой абстракцией с ограниченным интерфейсом. Такая мешанина невозможна при правильном проектировании.

xpahos ★★★★★
()
Ответ на: комментарий от xpahos

то что привел ТС невозможно в принципе. Ну только если очень много свободного времени и тестестерон уходит в скриптописание :-)

Задача есть, бюджет кажется огромным, сроки далёкими и начинаются извраты..:-)

MKuznetsov ★★★★★
()
Ответ на: комментарий от peregrine

Так. Двое сказали что норм. Но лично мне не нравится что у меня получилось именно так. На деле, хотя пример с вопросом главную проблему поднимает, все немного иначе:

Есть главный A в котором при определенных состояниях рождаются, живут и умирают B, C, D и E. Все они — наследники F. F знает про A, A знает про B, C, D и E. Иногда нужно, чтобы D узнал состояние C, а B иногда хочет знать как дела у C и D. E довольно часто, когда ему что-то сетнули, может сделать фикс в B и D, иначе значения конфликтуют (out of range). Короче вызовы из наследников F получаются такие: A->D()->getSome(); A->E()->setSome(value);

deep-purple ★★★★★
()
Последнее исправление: deep-purple (всего исправлений: 2)
Ответ на: комментарий от peregrine

Скорее нехорошо, но иногда никуда не деться

Deleted
()
Ответ на: комментарий от Kuzy

В зависимости от спецификаций ЯП это вообще может быть очень странной штукой. А проблем от этого очень немало, например, тыц. Но вообще можно терпеть их, если ЯП позволяет, но только в случае если зависимые друг от друга классы — плотно взаимодействующие части одного целого модуля, желательно не очень большого.

peregrine ★★★★★
()
Последнее исправление: peregrine (всего исправлений: 1)
Ответ на: комментарий от pavlick

Такое не скомпилируется. Вы забыли объявление void say(); в файле 1.cc, что будет являться практически явным указанием на намерение сделать рекурсию в том или ином виде.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.