Эта инициализация const через const_cast имеет неопределенное поведение? - PullRequest
7 голосов
/ 27 ноября 2010

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

РЕДАКТИРОВАТЬ: Мне действительно нравится идея в небольшом комментарии ybungalobill для метода инициализации этих больших объектов:

Ответы [ 3 ]

6 голосов
/ 27 ноября 2010

Вы изменяете объект, определенный как const.Неважно, когда вы это делаете, во время инициализации или нет, это все еще неопределенное поведение.Удаление constness с помощью 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 голосов
/ 27 ноября 2010

Вы неправильно используете оператор 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;

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

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

1 голос
/ 27 ноября 2010

Это 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;
}
...