#include <iostream>
int foo(int i){
return foo(i + 1);
}
int main(int argc,char * argv[]){
if(argc != 2){
return 1;
}
std::cout << foo(std::atoi(argv[1])) << std::endl;
}
% clang ++ -O2 test.cc
% времени ./a.out 42
1490723512
./a.out 42 0.00s пользователь 0.00s система 69% процессор 0.004 всего
% времени ./a.out 42
1564058296
./a.out 42 0.00s пользователь 0.00s система 56% процессор 0.006 всего
% g ++ -O2 test.cc
% ./a.out 42 # реинкурсия infinte
^ C
% clang++ --version
clang version 3.3 (tags/RELEASE_33/final)
Target: x86_64-apple-darwin12.4.0
Thread model: posix
% g++ --version
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Так это ошибка или особенность clang ++?
Хотя и g ++, и clang ++ способны компилировать код C ++ 98 и C ++ 11, clang ++ изначально разрабатывался как компилятор C ++ 11 и имеет некоторые поведения C ++ 11, встроенные в его ДНК (так сказать) ,
В C ++ 11 стандарт C ++ стал ориентирован на потоки, а это означает, что теперь существует определенное поведение потоков. В частности, 1.10 / 24 гласит:
Реализация может предполагать, что любой поток в конечном итоге выполнит одно из следующих действий:
— прекратить,
— сделать вызов функции ввода-вывода библиотеки,
— получить доступ или изменить изменчивый объект, или
— выполнить операцию синхронизации или атомарную операцию.
[Примечание: это предназначено для разрешения преобразований компилятора, таких как удаление пустых циклов, даже если завершение не может быть доказано. — конец примечания]
И это именно то, что делает Clang ++ при оптимизации. Он видит, что функция не имеет побочных эффектов и удаляет ее даже если это не заканчивается.
Других решений пока нет …