Перегрузка << оператор и рекурсия - PullRequest
5 голосов
/ 01 марта 2010

Я попробовал следующий код:

#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 внутри функции друга, рекурсия не произойдет. Почему это так?

Ответы [ 2 ]

7 голосов
/ 01 марта 2010

Оптимизатор решает, что все ваши оставшиеся действия не имеют никакого эффекта, и оптимизирует их. Правильно это или нет - другое дело.

В частности:

X x;

создает пустой объект "x"

* +1007 *

звонки:

return (os << obj);

который добавляет пустой объект; компилятор замечает, что 'os' не вырос с момента последнего вызова и не обещает делать это дальше (и больше ничего не происходит), поэтому он решает, что весь бизнес является избыточным и может быть обрезан в этот момент.

В случае, если вы звоните

    cout << "hehe";          // comment this and infinite loop is gone

есть дополнительная активность, поэтому оптимизатор не удаляет следующий вызов.

Полагаю, что если вы инициализировали x чем-то непустым или выполнили любое ненулевое действие, отличное от cout << "hehe";, рекурсия была бы запущена точно так же.

6 голосов
/ 01 марта 2010

В обоих случаях (с надписью «хе-хе» и без нее) Visual Studio 2005 выдает следующее предупреждение:

warning C4717: 'operator<<' : recursive on all control paths, function will cause runtime stack overflow

В обоих случаях он компилируется, и в обоих случаях он вызывает переполнение стека.

Однако без «хе-хе» переполнение стека происходит немного раньше.

...