Constポインタはいくつかの方法で宣言できることを理解しています。
const int * intPtr1; // Declares a pointer that cannot be changed.
int * const intPtr2; // Declares a pointer whose contents cannot be changed.
// EDIT: THE ABOVE CLAIMS ARE INCORRECT, PLEASE READ THE ANSWERS.
しかし、関数の引数のコンテキスト内で同じ原理はどうでしょうか?
以下は冗長だと思います。
void someFunc1(const int * arg);
void someFunc2(int * arg);
SomeFunc 1および2はポインター自体に値渡しを行うため、関数への特定の呼び出しでsomeFunc1が元のポインターの値を変更することは不可能です。説明する:
int i = 5;
int * iPtr = &i;
someFunc1(iPtr); // The value of iPtr is copied in and thus cannot be changed by someFunc1.
これらが真である場合、「const int * ptr」型の引数を持つ関数を宣言する意味はありません、正しいですか?
あなたはそれを逆に持っています:
const int * intPtr1; // Declares a pointer whose contents cannot be changed.
int * const intPtr2; // Declares a pointer that cannot be changed.
次のconst
は確かに不要であり、関数に入れる理由はありませんdeclaration:
void someFunc1(int * const arg);
ただし、ローカル変数(またはその他)const
を宣言するのと同じ理由で、関数implementationに配置することをお勧めします-実装はより簡単かもしれません特定の事柄が変わらないことがわかっているときにフォローする。関数の他の宣言でconst
が宣言されているかどうかに関係なく、これを行うことができます。
まあ、それは呼び出し側ではなく、someFunc1
。したがって、someFunc1
誤って変更しないでください。お気に入り
void someFunc1(int *arg) {
int i = 9;
arg = &i; // here is the issue
int j = *arg;
}
いくつかのケーススタディをしましょう:
1)先のとがった値をconstにするだけ
void someFunc1(const int * arg) {
int i = 9;
*arg = i; // <- compiler error as pointed value is const
}
2)ポインタをconstにするだけ
void someFunc1(int * const arg) {
int i = 9;
arg = &i; // <- compiler error as pointer is const
}
)関係する変数がconstである可能性がある場合にconstを使用する正しい方法:
void someFunc1(const int * const arg) {
int i = 9;
*arg = i; // <- compiler error as pointed value is const
arg = &i; // <- compiler error as pointer is const
}
これですべての疑問が解消されます。したがって、これは関数コード用であり、呼び出し元用ではないことをすでに述べたので、上記の3つのケースの中で最も制限的なものを使用する必要があります。
編集:
const
を宣言することをお勧めします。これにより、読みやすさが向上するだけでなく、呼び出し元もコントラクトを認識できるようになり、引数の不変性に関する信頼性が高まります。 (これは、一般的にヘッダーファイルを共有するために必要なbcozであるため、呼び出し元が実装のc/cppファイルを持たない場合があります)あなたはあなたの論理を間違った方法で持っています。型を逆に読む必要があるため、const int *
はconst int
へのポインターであり、int * const
はintへのconst
ポインターです。
例:
void foo() {
int a = 0;
int b = 0;
int * const ptrA = &a;
*ptrA = 1;
ptrA = &b; ///< Error
const int * ptrB = &a;
*ptrB = 1; ///< Error
ptrB = &b;
const int * const ptrC = &a;
*ptrC = 1; ///< Error
ptrC = &a; ///< Error
}
関数パラメーターをconst int *
にする理由を詳しく説明するには、関数として値を変更する必要があるため、呼び出し元にint
を渡す必要があることを示す必要があります。たとえば、次のコードを検討してください。
void someFunc1(const int * arg) {
// Can't change *arg in here
}
void someFunc2(int * arg) {
*arg = 5;
}
void foo() {
int a = 0;
someFunc1(&a);
someFunc2(&a);
const int b = 0;
someFunc1(&b);
someFunc2(&b); ///< *** Error here. Must pass in an int not a const int.
}
はい、あなたは正しいです(あなたがそれらを間違った方法で入手したという事実を無視して)-非参照const
パラメータをとっても意味がありません。さらに、参照以外のconst
値を返す意味はありません。
あなたはそれを間違った方法で持っています:
_const int * intPtr1; // Declares a pointer whose contents cannot be changed.
int * const intPtr2; // Declares a pointer that cannot be changed.
_
一般的に言えば、その表現を少し異なるように書くときの一貫性について推論するのは簡単です:_const int*
_は_int const *
_と同じ型です。その表記では、規則がはるかに明確になり、const
は常にその前の型に適用されるため、次のようになります。
_int const * intPtr1; // Declares a pointer to const int.
int * const intPtr2; // Declares a const pointer to int.
int const * * const * complexPtr; // A pointer to const pointer to pointer to const int
_
型が先頭にconst
を付けて書き込まれる場合、const
は最初の型の後に書き込まれたものとして処理されるため、_const T*
_は_T const *
_になります。
_void someFunc2(int * arg);
_
したがって、_someFunc2
_はarg
の内容を変更する可能性がありますが、_someFunc1
_は変更しない可能性があるため、冗長ではありません。 void someFunc3(int * const arg);
は冗長です(あいまいです)