2015-12-08 7 views
2

Мне просто интересно, почему этот код неверен? Он постоянно вызывает конструктор Foo и вызывает переполнение стека через некоторое время. Почему эта строка использования с ostream вызывает stackoverflow?

#include <iostream> 

    using namespace std; 

    class Foo 
    { 
     std::string str; 
    public: 
     Foo(const string& s) : str(s) 
     { 
      cout << "Foo constructor" << endl; 
     } 
     friend ostream& operator<<(ostream& os,const Foo& foo); 
    }; 

    ostream& operator<<(ostream& os,const Foo& foo) 
    { 
     os << foo.str; 
     return os; 
    } 

    int main() 
    { 
     Foo foo{"Hello"}; 
     cout << foo;  
     cin.get(); 
    } 

Я знаю, я знаю, что это нормально, чтобы написать

cout << foo.str << endl;

или os << foo.str.c_str();

, но я хочу знать, почему это происходит ошибка ..

+0

Все хорошо. Проблема должна быть в другом месте. – juanchopanza

+0

Возможно, это ошибка Visual C++? – ChaosDev

+0

Или что-то странное в 'cin.get()', которое вы, вероятно, должны удалить. – juanchopanza

ответ

3

Программа используйте std::string и его оператором вывода, но не включают заголовок <string>: при использовании <string> вам необходимо включить этот заголовок. Недостаточно то, что std::string определяется путем включения <iostream>. Он также не переносится: другая реализация может выбрать только объявление, но не определено std::string (требуется объявление, хотя некоторые члены IOStream используют тип std::string).

Если выходной оператор std::string не найден, то выражение

out << foo.str 

интерпретируется как как

out << Foo(foo.str) 

как есть это выходной оператор Foo. Конечно, это приводит к бесконечной рекурсии.

+0

Итак, iostream включает строку так же, как форвардное объявление, и правильное преобразование в ostream существует в заголовке ? – ChaosDev

+0

@ChaosDev: У меня нет MSVC++, поэтому я не знаю, что они делают точно. Он _seems_, как если бы включал '' делает _define_ 'std :: string' (иначе вы не смогли бы создать член этого типа), но не предоставляете все объявления из заголовка' '. Примечательно, что, похоже, в том числе '' does ** not ** предоставляет объявление оператора вывода 'std :: string', а' 'предоставляет этот оператор. –