который в конструкторе будет проверять callOnce на true и кидать исключение если надо, выставлять callOnce = true, а в деструкторе снова присваивать callOnce = false, тогда не надо будет руками нигде выставлять alreadyCalled
Если нужно детектировать рекурсию в любом месте кода, то можно использовать __cyg_profile_func_enter а в нем сравнивать адреса. Если два последних адреса функций совпали, значит это рекурсивный вызов.
у жцц есть расширение, которое позовляет определить адрес вызова, но даже если и так -- функция может себя вызвать рекурсивно через цепочку, а не сразу.
> С учетом нитей -- вопрос топикстартера поставлен не до конца.
До конца. Рекурсивный вызов по определению происходит на одном стеке (== в рамках одной нити). Все предложенные способы в присуствии нескольких нитей дают false positive.
> До конца. Рекурсивный вызов по определению происходит на одном стеке (== в рамках одной нити). Все предложенные способы в присуствии нескольких нитей дают false positive.
Формально подходя да. Но говоря "сделать нерекурсивной" топикстартер мог иметь ввиду "сделать нереентерабельной".
Пример со статической переменной не будет работать даже в случае двух независимых вызовов функции в разных нитях. В первом потоке при первом вхождении в функцию статическая переменная установится в true, если в то же время эта же функция будет вызвана во втором потоке, то приведенный код ошибочно посчитает такой вызов как рекурсивный.
>> С помощью шаблонов -- элементарно.
> продемонстрируйте плз
Оно хотя и элементарно, но
int i=non_reentrant<f,MyException,int,int>(1);
я уже написал, а чтобы писать
int i=non_reentrant<f,MyException>(1);
требуется почитать доки по бусту. И еще думаю потребуется boilerplate на разное к-во аргументов. Т.е. если кому вдруг очень интересно, напишу, а так лень.
Чтобы было non_recursive<f>(1) надо сделать thread-local вместо static, а в 4.4 его пока нет еще.
Как топиккастер уточняю. Функция может вызваться через цепочку. Однако, моя реальная задача была проще, так как перевызванная через цепочку из нитей функция должна тоже выдавать исключение.
В прочем, лично я, когда поразмыслил над этим всем, решил ограничиться простыми административными мерами. :-) Но вы можете продолжать...