2011-08-08 41 views
7

El siguiente código compila bien tanto con GCC (4.2-4.6) como con Clang (2.1), pero cuando ejecuto el ejecutable me da "Error de bus: 10". No entiendo la razón.const_cast de un miembro de const estático

#include <iostream> 

struct A 
{ 
    static int const v; 
    A() { ++*const_cast<int *>(&A::v); } 
}; 

int const A::v = 0; 

int main(int argc, char * argv[]) 
{ 
    A a, b, c; 
    std::cout << a.v << std::endl; 

    return 0; 
} 
+3

Estoy bastante seguro de que modificar algo que declare const es un comportamiento indefinido, pero estoy seguro de que alguien puede desenterrar la declaración precisa. –

+3

+1 para proporcionar un programa de muestra completo mínimo. Para obtener más información, consulte http://sscce.org/. –

Respuesta

12

creo que la cita relevante es:

§ 7.1.6.1 (4) from N3242:

Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.

Los ejemplos ilustran el punto usando const_cast. Como señaló James: la cita se puede encontrar en §7.1.5 en el estándar C++ 03.

Una pequeña elaboración: esa regla de lenguaje permite que el compilador use memoria de solo lectura (si está disponible en la arquitectura de destino) cuando algo se declara const. Sin esta regla, const -ness siempre se puede descartar sin temor a ninguna consecuencia y su uso solo sería una cuestión de disciplina del desarrollador. De esta forma, al menos puedes decirle a la gente que está invocando a UB, que generalmente es un buen elemento de disuasión. El const_cast es de menor importancia, ya que no importa cómo engañe al compilador para que le permita manipular un objeto const.

4

Porque no tiene permitido modificar las variables declaradas como const.

2

No tengo la solución para el problema real. Solo puedo decir, no use const_cast a menos que la intención sea llamar a una función miembro miembro de una función miembro no consistente y "const_cast" el resultado const (para que sea un resultado mutable para la función miembro no consistente).

Pero tengo una propuesta para mejorar su diseño:

class A 
{ 
private: 
    static int v; 
public: 
    A() { ++v; } 
    static int get_v() { return v; } 
}; 

int A::v = 0; 

int main(int argc, char * argv[]) 
{ 
    A a, b, c; 
    std::cout << a.get_v() << std::endl; 

    return 0; 
} 
1

El problema es esta línea:

static int const v; 

Debido a que la declaró const, el const_cast está provocando un comportamiento no definido - en su caso de que tenga suerte con el error de bus (es una falla de segmentación en mi sistema).

Declare que no const, y puede llamar a const_cast sin problemas.

2

El hecho de que haya descartado la const no significa que logre escribir en esa memoria.

Todo lo que const_cast<T> hace es eliminar la constidad de la variable desde la perspectiva del compilador. Eso permite que el compilador siga adelante y emita código para escribir en la variable. Pero en el tiempo de ejecución, si el compilador/vinculador coloca la variable en la memoria de solo lectura, el hardware le impedirá escribir allí, sin importar cómo lo lance.

6

5.2.11.7:

Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a const_cast that casts away a const-qualifier) may produce undefined behavior (7.1.5.1)

En su caso, usted está tratando de modificar los datos que están en el segmento de sólo lectura.

+1

Esta es una nota no normativa (es decir, es solo informativa). El texto normativo se encuentra en el §7.1.5.1 al que se hace referencia. –

+0

Es §7.1.6.1 en el borrador. Ver mi respuesta – pmr

+1

@pmr: Correcto, porque la especificación C++ 0x agrega una cláusula que define 'constexpr'. –

2

Básicamente, si se declara una variable const, el compilador puede emitir los resultados para leer solo la memoria. Tomar un puntero/referencia a un objeto const y luego usar const_cast para eliminar el const puede dar como resultado un comportamiento indefinido.

En general, solo es seguro usar const_cast si el objeto al que se hace referencia es no const (incluso si el puntero/referencia que tiene es const).

Cuestiones relacionadas