トップ回答者
ポインタの参照を関数に渡す場合の書式

質問
-
お世話になります。
ある関数に「ポインタの参照」を渡すケースについて考えています。
void foo()
{
int nTest = 10;
int *pnTest = &nTest;func1(pnTest);
// func2(pnTest);
// func3(pnTest);
// func4(pnTest);
}void func1(int *& pnVal)
{
// ポインタ自身も参照先の値も変更できる
*pnVal = 20;
pnVal = NULL;
}void func2(int const* const& pnVal)
{
// ポインタ自身も参照先の値も変更できない
*pnVal = 20; // コンパイルエラー!
pnVal = NULL; // コンパイルエラー!
}void func3(int * const& pnVal)
{
// 参照先の値は変更できるが、ポインタ自身は変更できない
*pnVal = 20;
pnVal = NULL; // コンパイルエラー!
}
ここまでは期待通りの結果なのですが、
以下のようにするとコンパイルエラーが表示されます。void func4(int const*& pnVal)
{
// ポインタ自身は変更できるが、参照先の値は変更できない
pnVal = NULL;
*pnVal = 20; // コンパイルエラー!
}error C2664: 'func4' : 1 番目の引数を 'int *' から 'const int *&' に変換できません。
「ポインタ自身は変更できるが参照先の値は変更できない」ような関数の
プロトタイプ宣言はどのように記述すればよいのでしょうか?
回答
-
すみません。2003では何もいいませんが、2008でやってみたら確かにerrになりますね。
エラーを出さないためにはconst修飾と&の参照渡しをどのように処理するか
明確に指定しなければならないようです。>のようにキャストする必要があるのでしょうか?
キャストでも十分ですが、本来の意味的には以下のコードと同等処理になるので、
テンプレートで吸収するか、キャスト専門のクラスを挟むしかないかもしれません。typedef int const* CPINT;
void func4( CPINT & pnVal)
{
pnVal = NULL;
// *pnVal = 20; // コンパイルエラー!
int nXXX = 0; // pnValとは無関係のコード
}void foo()
{
int nTest = 10;
CPINT p = &nTest;
func4( p);
} -
関数側ではconst int(のポインタの参照)だと(=中の値は変化しない)思っているのに実態がconstで無い場合、書き変ってしまう恐れがあるのでエラーになるのだと思います。
constは書き換えられない以外に、変化しないということも保証しています。
if (a == 0) {
処理1
}
if (a == 0) {
処理2
}
と、
if (a == 0) {
処理1
処理2
}
では、aがconstであるなら同じといえますが、
aがconstで無いなら同じでない(処理1や非同期で動作している部分でaが変化するかもしれないので)となります。
(つまり、constをはずすキャストは非常に危険だということです。)- 編集済み らーめん食べたいなぁ 2010年7月8日 6:36 括弧内を追記
- 回答の候補に設定 山本春海 2010年7月13日 5:36
- 回答としてマーク 山本春海 2010年7月14日 8:07
すべての返信
-
コメントありがとうございます。
説明の仕方が悪かったみたいで申し訳ありません。
func4()の場合には、以下のようにしてもコンパイルエラーになります。
ちなみに、VC++2010 Proでコンパイルしています。void foo()
{
int nTest = 10;
int *pnTest = &nTest;func4(pnTest);
}void func4(int const*& pnVal)
{
int nXXX = 0; // pnValとは無関係のコード
}これでもfoo()の中の「func4(pnTest);」の呼び出して以下のエラーになります。
error C2664: 'func4' : 1 番目の引数を 'int *' から 'const int *&' に変換できません。
やはり、func4の場合だけは呼び出し元で「foo((int const*&) pnTest);」
のようにキャストする必要があるのでしょうか? -
すみません。2003では何もいいませんが、2008でやってみたら確かにerrになりますね。
エラーを出さないためにはconst修飾と&の参照渡しをどのように処理するか
明確に指定しなければならないようです。>のようにキャストする必要があるのでしょうか?
キャストでも十分ですが、本来の意味的には以下のコードと同等処理になるので、
テンプレートで吸収するか、キャスト専門のクラスを挟むしかないかもしれません。typedef int const* CPINT;
void func4( CPINT & pnVal)
{
pnVal = NULL;
// *pnVal = 20; // コンパイルエラー!
int nXXX = 0; // pnValとは無関係のコード
}void foo()
{
int nTest = 10;
CPINT p = &nTest;
func4( p);
} -
関数側ではconst int(のポインタの参照)だと(=中の値は変化しない)思っているのに実態がconstで無い場合、書き変ってしまう恐れがあるのでエラーになるのだと思います。
constは書き換えられない以外に、変化しないということも保証しています。
if (a == 0) {
処理1
}
if (a == 0) {
処理2
}
と、
if (a == 0) {
処理1
処理2
}
では、aがconstであるなら同じといえますが、
aがconstで無いなら同じでない(処理1や非同期で動作している部分でaが変化するかもしれないので)となります。
(つまり、constをはずすキャストは非常に危険だということです。)- 編集済み らーめん食べたいなぁ 2010年7月8日 6:36 括弧内を追記
- 回答の候補に設定 山本春海 2010年7月13日 5:36
- 回答としてマーク 山本春海 2010年7月14日 8:07