Я попробовал следующий код:
#include <iostream>
using std::cout;
using std::ostream;
class X
{
public:
friend ostream& operator<<(ostream &os, const X& obj)
{
cout << "hehe"; // comment this and infinite loop is gone
return (os << obj);
}
};
int main()
{
X x;
cout << x;
return 0;
}
Когда я компилирую и выполняю это, это как ожидалось; бесконечный цикл. Если я удаляю cout
оператор в друге функционирует, рекурсии не происходит. Почему это так?
Оптимизатор решает, что все ваши оставшиеся действия не имеют никакого эффекта, и оптимизирует их. Правильно это или нет - другой вопрос.
В частности:
X x;
создает пустой объект «x»
cout << x;
вызывает:
return (os << obj);
, который добавляет пустой объект; компилятор замечает, что 'os' не выросла с момента последнего вызова, и не показывает никаких обещаний, что делает это дальше (и ничего больше не происходит), поэтому он решает, что весь бизнес избыточен и может быть сокращен на этом этапе.
Если вы вызываете
cout << "hehe"; // comment this and infinite loop is gone
, происходит некоторая дополнительная активность, поэтому оптимизатор не удаляет следующий вызов.
Думаю, если вы инициализируете x
чем-нибудь непустым или выполняете любое ненулевое действие, кроме cout << "хехе";
, у вас будет запущена рекурсия все равно.
В обоих случаях (с написанием «хе-хе» и без него) Visual Studio 2005 выдает следующее предупреждение:
warning C4717: 'operator<<' : recursive on all control paths, function will cause runtime stack overflow
В обоих случаях он компилируется и в обоих случаях это дает переполнение стека.
Однако без «хе-хе» переполнение стека происходит немного раньше.