const オブジェクトへの読み取り専用アクセスに const_cast を使用することは許可されていますか?
-
20-09-2019 - |
質問
C++ には、配列への読み取り専用アクセスのみを必要とする関数がありますが、誤って非 const ポインターを受け取るように宣言されています。
size_t countZeroes( int* array, size_t count )
{
size_t result = 0;
for( size_t i = 0; i < count; i++ ) {
if( array[i] == 0 ) {
++result;
}
}
return result;
}
そして、 const 配列に対してそれを呼び出す必要があります。
static const int Array[] = { 10, 20, 0, 2};
countZeroes( const_cast<int*>( Array ), sizeof( Array ) / sizeof( Array[0] ) );
これは未定義の動作になりますか?もしそうなら、プログラムはいつ UB に実行されますか? const_cast を実行して関数を呼び出すとき、または配列にアクセスするとき?
解決
はい、それが許されます。それは未定義の動作を招きconst
オブジェクトへの実際の書き込みではなく、キャスト自身(7.1.5.1/4 [dcl.type.cv])です。
で標準Notesなど5.2.11 / 7 [expr.const.cast]、オブジェクト未定義の動作を生成することができる離れconst
を鋳造した結果であるポインタを介して書き込む試みの種類に応じて
他のヒント
const_cast
を使って何をしているか知っているコンパイラを告げたので、、あなたは実際にはOKになります。しかし、私はあなたが技術的に未定義の動作を起動していると信じています。固定関数宣言を取得、または書き込み、それのconstのセーフバージョンを宣言して使用することをお勧めます。
はい、あなたはそれを行うことができます。いいえ、それは限り、本当に関数は、配列に書き込みをしようとしていないとして、未定義の動作ではありません。
の問題 const_cast
は常に同じです -- へのキャストとからのキャストと同じように、「ルールを破る」ことができます。 void*
-- 確かにそうすることはできますが、問題はなぜそうする必要があるのかということです。
この場合はもちろん大丈夫ですが、なぜ申告しなかったのか自問する必要があります。 size_t countZeroes( const int* array, size_t count )
そもそも?
そして、一般的なルールとして、 const_cast
:
- 見つけにくいバグが発生する可能性があります
- コンパイラとの const 合意を破棄することになります。
- 基本的に、言語を低レベルのものに変えることになります。
したがって、未定義の動作は、あなたがconst_cast
呼び出す時点ですぐに来る程度、const
はUBであるとして最初に定義されたオブジェクトにconst_cast
を使用します。