7

В соответствии с моими небольшими тестами этот код работает. Но имеет ли это неопределенное поведение? Изменение const-объекта с использованием const_cast привело к нарушениям во время выполнения во время предыдущих тестов, но я не помню, как они были разными. Итак, есть ли в принципе что-то неправильно или нет?Имеет ли эта инициализация const через const_cast неопределенное поведение?

// 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"); 
} 

(Обратите внимание, что SizeOf (bigLut_t) слишком много, чтобы поместиться в стек.)

EDIT: Я на самом деле нравится идея в ybungalobill годах небольшой комментарий для метода инициализации этих больших объектов:

// 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

Помимо остального, `недействительным main` является незаконным в C++. `main` должен ** всегда ** иметь тип возврата` int`. Однако вы можете спокойно опустить оператор `return`. – 2010-11-27 12:15:05

ответ

6

Вы изменяете объект, определенный как константы. Неважно, когда вы это делаете, во время инициализации или нет, это все еще неопределенное поведение. Удаление константы с const_cast определяется только в том случае, если указатель const был получен от указателя неконстантного объекта к этому объекту на каком-то раннем этапе. Это не твое дело.

Самое лучшее, что вы можете сделать, это

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(); 

и мы надеемся, что компилятор оптимизирует из статической временной.

3

Вы злоупотребляете оператор const_cast, который, к сожалению, возможно, и в этом случае порождает неопределенное поведение ... Вы можете использовать динамический инициализатор для constBigLut, вызывая его неявный конструктор копирования (в предположении, что boost::array такое же понятие, как std::array):

struct bigLut_tinit { 
    bigLut_t BigLut; 

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

const bigLut_tinit constBigLut; 

Edit: Кажется, что VC++ 10 прекрасно применяет РВО, так что временный непосредственно перемещается в статический объект длительности. Таким образом, имхо не нужно декларировать местную статику или ссылки на темпы ...

Редактировать 2: Да, я пропустил проблему с размером. Рекомендовать обертывание в нетривиальный тип с конструктором, как указано выше ...

+0

OP явно сказал, что «sizeof (bigLut_t) слишком много, чтобы вписаться в стек». – ybungalobill 2010-11-27 12:10:41

1

Это UB, потому что этот массив может быть сохранен в ПЗУ.

Вы можете сделать это:

// 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; 
}