Este es mi código de muestra:
#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;
}
Si comento #include <string>
, no obtengo ningún error de compilación, supongo que se incluye de alguna manera #include <iostream>
. Si hago "clic derecho -> Ir a definición" en Microsoft VS, ambos apuntan a la misma línea en el xstring
archivo:
typedef basic_string<char, char_traits<char>, allocator<char> >
string;
Pero cuando ejecuto mi programa, aparece un error de excepción:
0x77846B6E (ntdll.dll) en OperatorString.exe: 0xC00000FD: Desbordamiento de pila (Parámetro: 0x00000001, 0x01202FC4)
¿Alguna idea de por qué aparece un error de tiempo de ejecución al comentar #include <string>
? Estoy usando VS 2013 Express.
c++
string
stack-overflow
explicit
aerotransportado
fuente
fuente
#include<iostream>
y<string>
ambos podrían incluir<common/stringimpl.h>
....\main.cpp(23) : warning C4717: 'operator<<': recursive on all control paths, function will cause runtime stack overflow
al ejecutar esta líneacl /EHsc main.cpp /Fetest.exe
Respuestas:
De hecho, comportamiento muy interesante.
Con el compilador MS VC ++, el error ocurre porque si no lo hace, no
#include <string>
lo habráoperator<<
definidostd::string
.Cuando el compilador intenta compilar
ausgabe << f.getName();
busca unoperator<<
definido parastd::string
. Como no se definió, el compilador busca alternativas. Hay unoperator<<
definida porMyClass
y los intentos del compilador para usarlo, y para utilizarlo se tiene que convertirstd::string
aMyClass
y esto es exactamente lo que sucede porqueMyClass
tiene un constructor no explícito! Entonces, el compilador termina creando una nueva instancia de tuMyClass
e intenta transmitirlo nuevamente a tu flujo de salida. Esto resulta en una recursión sin fin:Para evitar el error necesitas
#include <string>
asegurarse de que haya unoperator<<
definido parastd::string
. También debe hacer que suMyClass
constructor sea explícito para evitar este tipo de conversión inesperada. Regla de sabiduría: haga explícitos a los constructores si toman solo un argumento para evitar la conversión implícita:Parece que
operator<<
para lastd::string
obtiene sólo cuando se define<string>
se incluye (con el compilador MS) y para que compila razón, todo, sin embargo, se obtiene un comportamiento algo inesperado ya queoperator<<
se llama de forma recursiva para conseguirMyClass
en lugar de llamaroperator<<
astd::string
.No, la cadena está completamente incluida, de lo contrario no podría usarla.
fuente
std::string
sin#include<string>
todo tipo de cosas, puede ocurrir, no limitado a un error de tiempo de compilación. Llamar a la función u operador incorrecto es aparentemente otra opción.El problema es que su código está haciendo una recursión infinita. El operador de transmisión para
std::string
(std::ostream& operator<<(std::ostream&, const std::string&)
) se declara en el<string>
archivo de encabezado, aunquestd::string
sí se declara en otro archivo de encabezado (incluido por ambos<iostream>
y<string>
).Cuando no incluye
<string>
el compilador intenta encontrar una manera de compilarausgabe << f.getName();
.Sucede que ha definido tanto un operador de transmisión
MyClass
como un constructor que admite astd::string
, por lo que el compilador lo usa (a través de la construcción implícita ), creando una llamada recursiva.Si declara
explicit
su constructor (explicit MyClass(const std::string& s)
), su código ya no se compilará, ya que no hay forma de llamar al operador de transmisiónstd::string
y se verá obligado a incluir el<string>
encabezado.EDITAR
Mi entorno de prueba es VS 2010, y comenzando en el nivel de advertencia 1 (
/W1
) le advierte sobre el problema:fuente