c++ - significa - system.stackoverflowexception c#
¿Por qué#include<string> evita un error de desbordamiento de pila aquí? (2)
De hecho, comportamiento muy interesante.
Alguna idea de por qué me aparece un error de tiempo de ejecución al comentar
#include <string>
Con el compilador MS VC ++, el error ocurre porque si no
#include <string>
no tendrá el
operator<<
definido para
std::string
.
Cuando el compilador intenta compilar
ausgabe << f.getName();
busca un
operator<<
definido para
std::string
.
Como no se definió, el compilador busca alternativas.
Hay un
operator<<
definido para
MyClass
y el compilador intenta usarlo, y para usarlo tiene que convertir
std::string
a
MyClass
y esto es exactamente lo que sucede porque ¡
MyClass
tiene un constructor no explícito!
Entonces, el compilador termina creando una nueva instancia de su
MyClass
e intenta transmitirlo nuevamente a su flujo de salida.
Esto resulta en una recursión sin fin:
start:
operator<<(MyClass) ->
MyClass::MyClass(MyClass::getName()) ->
operator<<(MyClass) -> ... goto start;
Para evitar el error, debe
#include <string>
para asegurarse de que haya un
operator<<
definido para
std::string
.
También debe hacer explícito su constructor
MyClass
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:
class MyClass
{
string figName;
public:
explicit MyClass(const string& s) // <<-- avoid implicit conversion
{
figName = s;
}
const string& getName() const
{
return figName;
}
};
Parece que el
operator<<
para
std::string
se define solo cuando se incluye
<string>
(con el compilador de MS) y por esa razón todo se compila, sin embargo, se obtiene un comportamiento inesperado ya que el
operator<<
se llama recursivamente para
MyClass
de llamar al
operator<<
para
std::string
.
¿
#include <iostream>
significa que a través de la cadena#include <iostream>
solo se incluye parcialmente?
No, la cadena está completamente incluida, de lo contrario no podría usarla.
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 del compilador, supongo que se incluye a través de
#include <iostream>
.
Si hago
"clic derecho -> Ir a definición"
en Microsoft VS, ambos apuntan a la misma línea en el archivo
xstring
:
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.
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 archivo de encabezado
<string>
, aunque
std::string
se declara en otro archivo de encabezado (incluido por
<iostream>
y
<string>
).
Cuando no incluye
<string>
el compilador intenta encontrar una manera de compilar
ausgabe << f.getName();
.
Sucede que ha definido tanto un operador de transmisión para
MyClass
como un constructor que admite una
std::string
, por lo que el compilador la 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ón con
std::string
, y se verá obligado a incluye el encabezado
<string>
.
EDITAR
Mi entorno de prueba es VS 2010, y comenzando en el nivel de advertencia 1 (
/W1
) le advierte sobre el problema:
advertencia C4717: ''operador <<'': recursivo en todas las rutas de control, la función provocará un desbordamiento de la pila en tiempo de ejecución