significa - errores en c++
¿Se produce un error en el código C++ debido a un comportamiento indefinido o error del compilador? (3)
Estoy experimentando choques extraños. Y me pregunto si es un error en mi código, o el compilador. Cuando compilo el siguiente código C ++ con Microsoft Visual Studio 2010 como una versión de lanzamiento optimizada, se bloquea en la línea marcada:
struct tup { int x; int y; };
class C
{
public:
struct tup* p;
struct tup* operator--() { return --p; }
struct tup* operator++(int) { return p++; }
virtual void Reset() { p = 0;}
};
int main ()
{
C c;
volatile int x = 0;
struct tup v1;
struct tup v2 = {0, x};
c.p = &v1;
(*(c++)) = v2;
struct tup i = (*(--c)); // crash! (dereferencing a NULL-pointer)
return i.x;
}
Mirando en el desmontaje, es obvio que debe bloquearse:
int _tmain(int argc, _TCHAR* argv[])
{
00CE1000 push ebp
00CE1001 mov ebp,esp
00CE1003 sub esp,0Ch
C c;
volatile int x = 0;
00CE1006 xor eax,eax
00CE1008 mov dword ptr [x],eax
struct tup v1;
struct tup v2 = {0, x};
00CE100B mov ecx,dword ptr [x]
c.p = &v1;
(*(c++)) = v2;
00CE100E mov dword ptr [ebp-8],ecx
struct tup i = (*(--c));
00CE1011 mov ecx,dword ptr [x]
00CE1014 mov dword ptr [v1],eax
00CE1017 mov eax,dword ptr [ecx]
00CE1019 mov ecx,dword ptr [ecx+4]
00CE101C mov dword ptr [ebp-8],ecx
return i.x;
}
00CE101F mov esp,ebp
00CE1021 pop ebp
00CE1022 ret
En la compensación 00CE1008 escribe un 0 en x.
En la compensación 00CE100B lee x (el 0) en ecx
En la compensación 00CE1017, se hace una desreferencia de ese puntero 0.
Veo dos posibles razones:
O bien hay un caso sutil (o no tan sutil?) De comportamiento indefinido en mi código y el compilador "optimiza" este comportamiento indefinido en una falla.
o hay un error de compilación
¿Alguien ve lo que podría causar el problema?
Gracias,
Jonas
EDITAR: Para abordar los comentarios relativos a "puntero a ubicación no válida"
Si cambio v1
para que sea struct tup v1[10];
y establece cp = &v1[0];
, entonces no habrá puntero a una ubicación inválida. Pero todavía puedo observar el mismo comportamiento. El desmontaje se ve ligeramente diferente, pero todavía hay un fallo y todavía es causado por cargar 0 en ecx y desreferirlo.
EDITAR: Conclusión
Por lo tanto, probablemente es un error. Descubrí que el accidente se desvanece si cambio
struct tup* operator--() { return --p; }
a
struct tup* operator--() { --p; return p; }
Como nos dice bames53, el bloqueo no se produce en VS2011 y concluye que debe haberse solucionado.
Sin embargo, decidí archivar ese error por dos razones:
El error aún podría estar presente en VS2011. Tal vez el optimizador simplemente haya cambiado de manera que mi código ya no active el error. (El error parece ser muy sutil, no se produce cuando
volative
elvolative
o elvirtual void Reset()
)Quiero saber si mi solución es una forma confiable de descartar los bloqueos, o si los cambios de código en otros lugares pueden reintroducir el error.
Aqui esta el link:
https://connect.microsoft.com/VisualStudio/feedback/details/741628/error-in-code-generation-for-x86
El código está bien. Es un error de compilación.
El código *(c++) = v2
hará un postpensado de cp
con el valor original. Ese valor fue asignado en la línea anterior y es &v1
. Entonces, en efecto, hace v1 = v2;
, que está perfectamente bien.
cp
ahora se comporta como un pasaje único de una matriz de un elemento que contiene solo v1
, por §5.7p4 del estándar:
Para los fines de estos operadores [
+
y-
], un puntero a un objeto que no es una matriz se comporta igual que un puntero al primer elemento de una matriz de longitud uno con el tipo del objeto como su tipo de elemento.
Luego, *(--c)
mueve el puntero de nuevo a &v1
y lo desactiva, lo que también está bien.
No tiene que ser UB o error del compilador. No puede ser debido a la forma en que se produjo VS2010.
Estrictamente hablando, su programa exhibe un comportamiento bien definido. Sin embargo, eso podría ser solo de acuerdo con el estándar C ++ más nuevo. VS2010 solo se implementa contra un borrador de Norma que puede no haber incluido esta disposición. Si no lo hizo, entonces su código no es UB, pero VS no es incorrecto para producir UB, ya que esos eran los requisitos del momento en que se realizó.
Por supuesto, si ha sido legal tratar los objetos de la pila como una matriz de un objeto en C ++ 03, entonces es un error del compilador.
Edición: si aún obtienes el fallo de una matriz como lo indicas, entonces ese es definitivamente un error del compilador.
Usted toma &v1
en cp y luego usa el operador ++ lo avanza. No puede confiar en el orden de la pila, por lo tanto, viene un comportamiento indefinido ( (&v1)+1 != &v2
)