• ベストアンサー

const で宣言してるのに、値が変更できてしまう

constを使って、配列のアドレス&値の変更を禁止させたのですが 以下のコードを書くと変更できてしまいます。(テスト環境は、Visual C++ .NET 2003 です。) void CtestDlg::myAAA() { char hoge[] = {1,2,3}; const char const *kari = hoge; //配列kariからは変更不可 myBBB(kari); //配列kariのアドレスを渡す } void CtestDlg::myBBB(const char const *pBuffer) { //pBuffer[1] = 99; //これをするとエラー *(int*)pBuffer = 6;; //キャスト //元のhoge配列の中身も変わっている } const の用途は、「変更できない」じゃなくて「変更しちゃだめ」って注意を促す だけなのでしょうか?? そもそも何がやりたいかと言いますと、 例えば、myAAA関数とmyBBB関数をそれぞれ違う人が記述する場合、 myBBB関数 の作成者がどんなコードを書いても配列hogeが上書きされないように myAAA関数で変更禁止処理をかけたいのですが・・・アドレスを渡す時点でそれは不可能なのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • MrBan
  • ベストアンサー率53% (331/615)
回答No.2

どちらかといえば、「変更しちゃだめ」です。 そして、通常はそれで十分に変更禁止の役に立ちます。 例示の「強引なキャスト」はルールを破る数少ない手段です。 > *(int*)pBuffer = 6;; //キャスト 変更できるのは、(int*)で*無理やり* constでない型にキャストしているためです。 (int*)のようなキャストはC言語との互換性のために残っている代物で、 constを無理やりはずすことができますので、*そんなコードを書く奴が悪い*ということになります。 # C++用に用意されたキャストでは、const_castという専用のキャストが必要です。 # そして、const外しは未定義動作になる可能性も含め通常やるべきものではありません。 基本的にC++はプログラマは全能である、 コンパイラはありがちなミスを避けるための規制をかけるが、 プログラマは必要に応じて*明示的に*その制限を回避する手段がある、 ということが多いです。 言語はプログラマの意図を表現するための道具であり、 プログラマの意図を正しく表現できない言語は実用的でない、 という思想だと理解しています。

hiroki_xxx
質問者

お礼

詳しい解説ありがとうございます。 偶然見つけたのですが、既知の事実だったのですね・・。 「const外し」で検索したら一杯引っ掛かりました。 const外しはバグではなく、(思想的観点から)敢えて残しているのですね。

その他の回答 (4)

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.5

>早速の回答ありがとうございます。 >このやり方では保証できないのですね。 どうも勘違いしているような気がしてならない。 保証する責任を負っているのは myBBB() の実装担当者です。 myAAA() 実装担当者ができることは、CtestDlg::myBBB(const char* pBuffer) が「そのインターフェイス設計に反して」pBuffer の指す内容を変更してしまうと知った時点で、 そのバグを myBBB() の実装担当者に修正するよう要求することだけです。

  • tokichim
  • ベストアンサー率42% (88/205)
回答No.4

constについては他の回答者さんが回答されているので。 > myBBB関数 の作成者がどんなコードを書いても配列hogeが上書きされないように > myAAA関数で変更禁止処理をかけたいのですが・・・アドレスを渡す時点でそれは不可能なのでしょうか? そうですね、むしろmyAAAの作者はhogeへのポインタをそのまま渡さないようにする。 配列hogeに対応するクラスをつくり、hogeを操作するメソッドを実装してmyBBBの作者にはそれを使ってhogeにアクセスしてもらう。 そうすればmyAAAの作者はメソッドを実装する手間がかかる代わり、自分が公開した処理だけをそのクラスを使う者に許すことが出来ます。 安全性でいえばこれがスマートだと思うのですが、いかがでしょう?

hiroki_xxx
質問者

お礼

間接的に操作させるイメージでいいのでしょうか? 例では、簡単のため同クラスの関数で書いたのですが、それぞれ別クラスの場合 アクセス方向が myAAA⇔myBBB, myAAA→myBBB, myAAA←myBBB の場合でいろんな方法がありそうですね。 参考にしてみたら?というページがありましたら是非教えて下さい。 回答頂けた方どうもありがとうございました。

  • tadys
  • ベストアンサー率40% (856/2135)
回答No.3

>myAAA関数で変更禁止処理をかけたいのですが・・・アドレスを渡す時点でそれは不可能なのでしょうか? それはシステムに依存します。 組み込み系では const を ROM 上に配置するするものがありますがその場合は物理的に書き込み出来ません。 また、MMUで書込み禁止に設定できる場合は書き込みをしたときに例外が発生するように出来ます。 そうでない場合には禁止できませんね。 どうしても禁止したいのであればポインタで渡すのをやめるしかないでしょう。

hiroki_xxx
質問者

お礼

組み込み系だと、const宣言時にROMに割り当てられるので上書不可なんですね。 ただ、組み込み開発の環境があったので試しにコンパイルしてみたら 通りました(汗)。一応、警告はでましたが・・・

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.1

>myBBB関数 の作成者がどんなコードを書いても配列hogeが上書きされないように >myAAA関数で変更禁止処理をかけたい インターフェイスを void CtestDlg::myBBB(const char* pBuffer) と宣言して、myBBB() を実装する以上、 *pBuffer の内容が変更されないようにするのは、「myBBB の作成者の責任」だと思いますよ。

hiroki_xxx
質問者

お礼

早速の回答ありがとうございます。 このやり方では保証できないのですね。