7

私の小さなテストによると、このコードは機能します。しかし、それは未定義の振る舞いを持っていますか?const_castを使用してconstオブジェクトを変更すると、以前のテストで実行時アクセス違反が発生しましたが、それらがどのように異なっていたかを思い出せません。それで、ここに根本的に何か問題があるのでしょうか?

// 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)が大きすぎてスタックに収まらないことに注意してください。)

編集:私は実際、これらの大きなオブジェクトを初期化する方法として、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;
    }
}
4

3 に答える 3

6

const として定義されたオブジェクトを変更します。初期化中かどうかに関係なく、いつ実行するかは問題ではありませんが、まだ未定義の動作です。const_cast を使用した constness の削除は、const ポインターが以前の段階でそのオブジェクトへの非 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();

うまくいけば、コンパイラは静的一時を最適化します。

于 2010-11-27T11:44:35.577 に答える
3

残念ながら可能性のある const_cast 演算子を誤用しており、この場合、未定義の動作が生成されます...暗黙のコピーコンストラクターを呼び出すことで、動的イニシャライザーを使用できます(それが と同じ概念であるとconstBigLut仮定します):boost::arraystd::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: ええ、サイズの問題を見逃していました。上記のように、コンストラクターを使用して自明でない型にラップすることをお勧めします...

于 2010-11-27T11:51:21.763 に答える
1

その配列はROMに格納できるため、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;
}
于 2010-11-27T11:53:21.293 に答える