前置き
constとポインタの関係について調べたので、その記録を残します。
実験などしなくとも、今はネット上でいくらでも解説サイトがあります。
しかしながら今回はあえて実験し、そこから法則性を求めることにした。
実際にコンパイルし、エラーとなる書き方を探る
まず、下記のソースをコンパイルして、どこでエラーが発生するか試す。
source : ptr_cnst.cpp
# include <iostream>
# include <string>
int main()
{
using std::literals::string_literals::operator""s;
char str1_1[] = "char[] test1-1.";
char str2_1[] = "char[] test2-1.";
char str3_1[] = "char[] test3-1.";
char str4_1[] = "char[] test4-1.";
char str5_1[] = "char[] test5-1.";
char str6_1[] = "char[] test6-1.";
char str7_1[] = "char[] test7-1.";
char str8_1[] = "char[] test8-1.";
char str1_2[] = "char[] test1-2.";
char str2_2[] = "char[] test2-2.";
char str3_2[] = "char[] test3-2.";
char str4_2[] = "char[] test4-2.";
char str5_2[] = "char[] test5-2.";
char str6_2[] = "char[] test6-2.";
char str7_2[] = "char[] test7-2.";
char str8_2[] = "char[] test8-2.";
char *p_ch1 = str1_1;
const char *p_ch2 = str2_1;
char const*p_ch3 = str3_1;
char *const p_ch4 = str4_1;
const char const * p_ch5 = str5_1;
char const *const p_ch6 = str6_1;
const char *const p_ch7 = str7_1;
const char const *const p_ch8 = str8_1;
p_ch1 = str1_2;
p_ch2 = str2_2;
p_ch3 = str3_2;
p_ch4 = str4_2;
p_ch5 = str5_2;
p_ch6 = str6_2;
p_ch7 = str7_2;
p_ch8 = str8_2;
*p_ch1 = '@';
*p_ch2 = '@';
*p_ch3 = '@';
*p_ch4 = '@';
*p_ch5 = '@';
*p_ch6 = '@';
*p_ch7 = '@';
*p_ch8 = '@';
std::cout << p_ch1 << std::endl;
std::cout << p_ch2 << std::endl;
std::cout << p_ch3 << std::endl;
std::cout << p_ch4 << std::endl;
std::cout << p_ch5 << std::endl;
std::cout << p_ch6 << std::endl;
std::cout << p_ch7 << std::endl;
std::cout << p_ch8 << std::endl;
}
下記のコンパイルエラーが発生しました。
$ g++ -std=c++20 -Wall -pedantic-errors ./ptr_cnst.cpp -o ./ptr_cnst.exe
./ptr_cnst.cpp: In function 'int main()':
./ptr_cnst.cpp:29:13: error: duplicate 'const'
29 | const char const * p_ch5 = str5_1;
| ^~~~~
| -----
./ptr_cnst.cpp:32:13: error: duplicate 'const'
32 | const char const *const p_ch8 = str8_1;
| ^~~~~
| -----
./ptr_cnst.cpp:37:8: error: assignment of read-only variable 'p_ch4'
37 | p_ch4 = str4_2; // error: assignment of read-only variable 'p_ch4'
| ~~~~~~^~~~~~~~
./ptr_cnst.cpp:39:8: error: assignment of read-only variable 'p_ch6'
39 | p_ch6 = str6_2;
| ~~~~~~^~~~~~~~
./ptr_cnst.cpp:40:8: error: assignment of read-only variable 'p_ch7'
40 | p_ch7 = str7_2;
| ~~~~~~^~~~~~~~
./ptr_cnst.cpp:41:8: error: assignment of read-only variable 'p_ch8'
41 | p_ch8 = str8_2;
| ~~~~~~^~~~~~~~
./ptr_cnst.cpp:44:9: error: assignment of read-only location '* p_ch2'
44 | *p_ch2 = '@'; // error: assignment of read-only location '* p_ch2'
| ~~~~~~~^~~~~
./ptr_cnst.cpp:45:9: error: assignment of read-only location '* p_ch3'
45 | *p_ch3 = '@'; // error: assignment of read-only location '* p_ch3'
| ~~~~~~~^~~~~
./ptr_cnst.cpp:47:9: error: assignment of read-only location '* p_ch5'
47 | *p_ch5 = '@';
| ~~~~~~~^~~~~
./ptr_cnst.cpp:48:9: error: assignment of read-only location '*(const char*)p_ch6'
48 | *p_ch6 = '@';
| ~~~~~~~^~~~~
./ptr_cnst.cpp:49:9: error: assignment of read-only location '*(const char*)p_ch7'
49 | *p_ch7 = '@';
| ~~~~~~~^~~~~
./ptr_cnst.cpp:50:9: error: assignment of read-only location '*(const char*)p_ch8'
50 | *p_ch8 = '@';
| ~~~~~~~^~~~~
エラー箇所をコメントアウトし、コンパイルを通す
下記のようにエラー行をコメントアウトするとコンパイルが通った。
source : ptr_cnst.cpp
# include <iostream>
# include <string>
int main()
{
using std::literals::string_literals::operator""s;
char str1_1[] = "char[] test1-1.";
char str2_1[] = "char[] test2-1.";
char str3_1[] = "char[] test3-1.";
char str4_1[] = "char[] test4-1.";
// char str5_1[] = "char[] test5-1.";
char str6_1[] = "char[] test6-1.";
char str7_1[] = "char[] test7-1.";
// char str8_1[] = "char[] test8-1.";
char str1_2[] = "char[] test1-2.";
char str2_2[] = "char[] test2-2.";
char str3_2[] = "char[] test3-2.";
char str4_2[] = "char[] test4-2.";
// char str5_2[] = "char[] test5-2.";
char str6_2[] = "char[] test6-2.";
char str7_2[] = "char[] test7-2.";
// char str8_2[] = "char[] test8-2.";
char *p_ch1 = str1_1;
const char *p_ch2 = str2_1;
char const*p_ch3 = str3_1;
char *const p_ch4 = str4_1;
// const char const * p_ch5 = str5_1; // error: duplicate 'const'
char const *const p_ch6 = str6_1;
const char *const p_ch7 = str7_1;
// const char const *const p_ch8 = str8_1; // error: duplicate 'const'
p_ch1 = str1_2;
p_ch2 = str2_2;
p_ch3 = str3_2;
// p_ch4 = str4_2; // error: assignment of read-only variable 'p_ch4'
// p_ch5 = str5_2;
// p_ch6 = str6_2; // error: assignment of read-only variable 'p_ch6'
// p_ch7 = str7_2; // error: assignment of read-only variable 'p_ch7'
// p_ch8 = str8_2;
*p_ch1 = '@';
// *p_ch2 = '@'; // error: assignment of read-only location '* p_ch2'
// *p_ch3 = '@'; // error: assignment of read-only location '* p_ch3'
*p_ch4 = '@';
// *p_ch5 = '@';
// *p_ch6 = '@'; // error: assignment of read-only location '*(const char*)p_ch6'
// *p_ch7 = '@'; // error: assignment of read-only location '*(const char*)p_ch7'
// *p_ch8 = '@';
std::cout << p_ch1 << std::endl;
std::cout << p_ch2 << std::endl;
std::cout << p_ch3 << std::endl;
std::cout << p_ch4 << std::endl;
// std::cout << p_ch5 << std::endl;
std::cout << p_ch6 << std::endl;
std::cout << p_ch7 << std::endl;
// std::cout << p_ch8 << std::endl;
}
実行結果:
$ g++ -std=c++20 -Wall -pedantic-errors ./ptr_cnst.cpp -o ./ptr_cnst.exe
./ptr_cnst.cpp: In function 'int main()':
./ptr_cnst.cpp:19:7: warning: unused variable 'str4_2' [-Wunused-variable]
19 | char str4_2[] = "char[] test4-2.";
| ^~~~~~
./ptr_cnst.cpp:21:7: warning: unused variable 'str6_2' [-Wunused-variable]
21 | char str6_2[] = "char[] test6-2.";
| ^~~~~~
./ptr_cnst.cpp:22:7: warning: unused variable 'str7_2' [-Wunused-variable]
22 | char str7_2[] = "char[] test7-2.";
| ^~~~~~
$ ./ptr_cnst.exe
@har[] test1-2.
char[] test2-2.
char[] test3-2.
@har[] test4-1.
char[] test6-1.
char[] test7-1.
実行結果まとめ
先ほどの実行結果を表にまとめると下記のようになる。
constの付け方 | 変数の定義 | ポインタの指す先 ("アドレス")を変更 |
ポインタの指す先の "値"を変更 |
---|---|---|---|
char *p_ch1 |
可能 | 可能 | 可能 |
const char *p_ch2 |
可能 | 可能 | 不可能 |
char const*p_ch3 |
可能 | 可能 | 不可能 |
char *const p_ch4 |
可能 | 不可能 | 可能 |
const char const * p_ch5 |
不可能 | ― | ― |
char const *const p_ch6 |
可能 | 不可能 | 不可能 |
const char *const p_ch7 |
可能 | 不可能 | 不可能 |
const char const *const p_ch8 |
不可能 | ― | ― |
constとポインタの関係【結論】
constの位置 | 動作 |
---|---|
*の前 | ポインタの指す先の**"値"**の変更が不可 |
*の後 | ポインタの指す先("アドレス")の変更が不可 |
つまりconstが*の後にあるか、前にあるかで動作が変わるということである。