Este é o meu código de exemplo:
#include <iostream>
#include <string>
using namespace std;
class MyClass
{
string figName;
public:
MyClass(const string& s)
{
figName = s;
}
const string& getName() const
{
return figName;
}
};
ostream& operator<<(ostream& ausgabe, const MyClass& f)
{
ausgabe << f.getName();
return ausgabe;
}
int main()
{
MyClass f1("Hello");
cout << f1;
return 0;
}
Se eu comentar #include <string>
, não obtenho nenhum erro do compilador, acho que é meio que incluído #include <iostream>
. Se eu clicar com o botão direito do mouse -> Ir para definição no Microsoft VS, ambos apontam para a mesma linha no xstring
arquivo:
typedef basic_string<char, char_traits<char>, allocator<char> >
string;
Mas quando executo meu programa, recebo um erro de exceção:
0x77846B6E (ntdll.dll) no OperatorString.exe: 0xC00000FD: estouro de pilha (parâmetro: 0x00000001, 0x01202FC4)
Alguma idéia de por que recebo um erro de tempo de execução ao comentar #include <string>
? Estou usando o VS 2013 Express.
c++
string
stack-overflow
explicit
transportado pelo ar
fonte
fonte
#include<iostream>
e<string>
ambos podem incluir<common/stringimpl.h>
....\main.cpp(23) : warning C4717: 'operator<<': recursive on all control paths, function will cause runtime stack overflow
ao executar esta linhacl /EHsc main.cpp /Fetest.exe
Respostas:
De fato, comportamento muito interessante.
Com o compilador MS VC ++, o erro ocorre porque, caso contrário,
#include <string>
você não teráoperator<<
definidostd::string
.Quando o compilador tenta compilar,
ausgabe << f.getName();
ele procura por umoperator<<
definidostd::string
. Como não foi definido, o compilador procura alternativas. Existe umoperator<<
definido paraMyClass
e o compilador tenta usá-lo, e para usá-lo, ele deve ser convertidostd::string
emMyClass
e é exatamente isso que acontece porqueMyClass
tem um construtor não explícito! Portanto, o compilador acaba criando uma nova instância suaMyClass
e tenta transmiti-la novamente para o fluxo de saída. Isso resulta em uma recursão infinita:Para evitar o erro, você precisa
#include <string>
garantir que haja umoperator<<
definido parastd::string
. Você também deveMyClass
explicitar seu construtor para evitar esse tipo de conversão inesperada. Regra de sabedoria: torne os construtores explícitos se eles tiverem apenas um argumento para evitar a conversão implícita:Parece que
operator<<
parastd::string
recebe apenas definido quando<string>
está incluído (com o compilador MS) e por isso tudo compila, no entanto você tem um comportamento um tanto inesperado, comooperator<<
está sendo chamado de forma recursiva paraMyClass
em vez de chamaroperator<<
parastd::string
.Não, a string está totalmente incluída, caso contrário você não poderá usá-la.
fonte
std::string
sem#include<string>
todos os tipos de coisas pode acontecer, não se limita a um erro de tempo de compilação. Chamar a função ou operador errado é aparentemente outra opção.O problema é que seu código está fazendo uma recursão infinita. O operador de streaming para
std::string
(std::ostream& operator<<(std::ostream&, const std::string&)
) é declarado no<string>
arquivo de cabeçalho, emborastd::string
ele próprio seja declarado em outro arquivo de cabeçalho (incluído por ambos<iostream>
e<string>
).Quando você não inclui,
<string>
o compilador tenta encontrar uma maneira de compilarausgabe << f.getName();
.Acontece que você definiu um operador de streaming para
MyClass
e um construtor que admite astd::string
; portanto, o compilador o usa (por meio de construção implícita ), criando uma chamada recursiva.Se você declarar
explicit
seu construtor (explicit MyClass(const std::string& s)
), seu código não será mais compilado, pois não há como chamar o operador de streamingstd::string
e você será forçado a incluir o<string>
cabeçalho.EDITAR
Meu ambiente de teste é o VS 2010 e, iniciando no nível de aviso 1 (
/W1
), avisa sobre o problema:fonte