7

Según mis pequeñas pruebas, este código funciona. Pero, ¿tiene un comportamiento indefinido? La modificación del objeto const mediante el uso de const_cast dio como resultado violaciones de acceso en tiempo de ejecución en mis pruebas anteriores, pero no recuerdo cómo fueron diferentes. Entonces, ¿hay algo fundamentalmente malo aquí o no?¿Esta inicialización de const a través de const_cast tiene un comportamiento indefinido?

// test.h 
#pragma once 
#include <boost/array.hpp> 

typedef boost::array<int,100000> bigLut_t; 
extern const bigLut_t constBigLut; 

// test.cpp 
#include "test.h" 

bigLut_t& initializeConstBigLut() 
{ 
    bigLut_t* pBigLut = const_cast<bigLut_t*>(&constBigLut); 

    for(int i = 0; i < 100000; ++i) { 
     pBigLut->at(i) = i; 
    } 
    return const_cast<bigLut_t&>(constBigLut); 
} 

const bigLut_t constBigLut = initializeConstBigLut(); 

// const_test.cpp 
#include <iostream> 
#include "test.h" 

void main() 
{ 
    for(int i = 0; i < 100; ++i) { 
     std::cout << constBigLut[i] << std::endl; 
    } 
    system("pause"); 
} 

(Nótese que sizeof (bigLut_t) es demasiado para caber en la pila.)

EDIT: hecho, me gusta la idea en la ybungalobill pequeño comentario mejor para un método de inicialización de estos objetos grandes:

// test.h 
#pragma once 
#include <boost/array.hpp> 

extern const struct BigLut : public boost::array<int,100000> { 
    BigLut(); 
} constBigLut; 

// test.cpp 
#include "test.h" 

const BigLut constBigLut; 
BigLut::BigLut() 
{ 
    for(int i = 0; i < 100000; ++i) { 
     this->at(i) = i; 
    } 
} 
+6

aparte del resto, 'void main' es ilegal en C++. 'main' debe ** siempre ** tener return type' int'. Sin embargo, puedes omitir la declaración 'return'. –

Respuesta

6

modifica un objeto definido como const. No importa cuándo lo hagas, durante la inicialización o no, sigue siendo un comportamiento indefinido. La eliminación de la constness con const_cast se define solo si el puntero const se obtuvo desde un puntero no const a ese objeto en alguna etapa anterior. Ese no es tu caso.

Lo mejor que puede hacer es

const bigLut_t& initializeConstBigLut() 
{ 
    static bigLut_t bigLot; 

    for(int i = 0; i < 100000; ++i) { 
     bigLut.at(i) = i; 
    } 
    return bigLut; 
} 

const bigLut_t constBigLut = initializeConstBigLut(); 

y es de esperar que el compilador optimizará el temporal estática.

3

Se están haciendo mal uso del operador const_cast que desgraciadamente es posible, y en este caso genera un comportamiento indefinido ... Usted puede utilizar inicializador dinámico para constBigLut invocando su copia implícita constructor (suponiendo que boost::array es el mismo concepto que std::array):

struct bigLut_tinit { 
    bigLut_t BigLut; 

    bigLut_tinit() { 
    for(int i = 0; i < 100000; ++i) { 
     BigLut[i] = i; 
    } 
    } 
}; 

const bigLut_tinit constBigLut; 

Editar: Parece que VC++ 10 se aplica perfectamente RVO, de modo que el temporal se mueve directamente en el objeto duración estática. Así que no es necesario declarar estadísticas locales o referencias a las temp ...

Editar 2: Sí, me perdí el problema de tamaño. Recomendamos envolver en un tipo no trivial con constructor como el anterior ...

+0

El OP dijo explícitamente que "sizeof (bigLut_t) es demasiado para caber en la pila". – ybungalobill

+1

+1 para la idea de estructura. En realidad, puedes hacerlo aún mejor: hacer que la estructura se derive de bigLut_t, y luego el código que usa constBigLut será desencadenado. – ybungalobill

+0

En realidad, no haría algo así ... objetos de duración estática solo deberían ser una solución de emergencia absolutamente excepcional. Derivar el formulario 'std :: array' haría que incluso el 'HACKER' en mi humilde opinión, ya que claramente violaría el propósito de la herencia. Si algo como esto se vuelve necesario, es probable que tenga algún tipo de problema arquitectónico, que debería resolverse primero.Si eso no funciona, ajuste algo como la instancia 'bigLut_tinit' en un singleton seguro, para que no se pueda usar indebidamente ... –

1

Es un UB, porque esa matriz podría almacenarse en la ROM.

Usted puede hacer esto:

// test.h 
#include <boost/array.hpp> 

typedef boost::array<int,100000> bigLut_t; 
const bigLut_t& Lut(); 


// test.cpp 
#include "test.h" 

bool initialized=false; 

const bigLut_t& Lut() 
{ 
    static bigLut_t lut; 

    if (!initialized) 
    { 
    for(int i = 0; i < 100000; ++i) { 
     lut.at(i) = i; 
    } 
    } 
    return lut; 
} 
Cuestiones relacionadas