Search code examples
c++initializationundefinedundefined-behaviorconst-cast

Does this const initialization through const_cast have undefined behaviour?


According to my small tests this code works. But, does it have undefined behaviour? Modifying the const object through the use of const_cast resulted in run-time access violations in my previous tests, but I can't remember how they were different. So, is there fundamentally something wrong here or not?

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

(Notice that sizeof(bigLut_t) is too much to fit into the stack.)

EDIT: I actually like the idea in ybungalobill's small comment best for a method of initializing these big objects:

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

Solution

  • You modify an object defined as const. It doesn't matter when you do it, during initialization or not, it's still undefined behavior. Removing constness with const_cast is defined only if the const pointer was obtained from a non-const pointer to that object at some earlier stage. That's not your case.

    The best thing you can do is

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

    and hopefully the compiler will optimize out the static temporary.