作者museangel (敲敲)
看板C_and_CPP
标题[问题] 顶层、低层const
时间Sun Jun 20 02:29:36 2021
开发平台(Platform): (Ex: Win10, Linux, ...)
Win10
问题
刚入门学习C++,
C++ Primer, 5e, 2.4.3顶层的const小节提到:
「当我们拷贝一个物件,顶层const会被忽略。」
「另一方面,低层const永远都不会被忽略。」
其中有个举例:
const int ci = 42;
int &r = ci;//错误
1.「顶层const会被忽略、而低层就永远不会」这个原则是从哪里产生的呢?
为什麽不要一律保留const,而要区别顶层低层,并且有忽略跟保留的差异,
这是为了解决什麽问题吗?
2.为什麽ci的顶层const没有被忽略呢?如果照顶层const会被忽略的原则,
应该可以将普通int&系结到const int物件上,为什麽不行呢?
是因为参考并没有涉及拷贝的动作,单纯只是给另一个变数加上别名而已,
所以就没有忽略顶层const这件事吗?
请板上的大师们不吝教导,看了好几篇文章还是不理解为什麽要有这种机制...
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 111.251.33.237 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1624127378.A.D92.html
※ 编辑: museangel (111.251.33.237 台湾), 06/20/2021 02:41:52
1F:→ nh60211as: 你那不是拷贝物件,是取得物件的reference 06/20 02:39
2F:→ museangel: 对耶 真的忽略这件事...@@ 06/20 02:43
3F:→ museangel: 另外为什麽要有区分顶层跟低层的机制呢 怎麽不都保留呢 06/20 02:44
4F:推 LPH66: 这里应该是指一个指标本身的常数性和指标指向值的常数性 06/20 03:06
5F:→ LPH66: 常数性这种事是绑在变数上的, 只要有一个方式参照变数 06/20 03:06
6F:→ LPH66: 那就能谈论这个参照存取的常数性 (不可变性) 06/20 03:06
7F:→ LPH66: 但当我们 assign 值出来时, 我们是复制值 06/20 03:07
8F:→ LPH66: 因此这最顶层变数参照被我们解参照了, 其常数性不再有意义 06/20 03:08
9F:→ LPH66: 因此讲忽略有点简略, 因为会忽略的原因是解参照取值了 06/20 03:09
10F:→ LPH66: 在这个例子里, int& 这是一个 C++ 参照, 参照一个变数 06/20 03:10
11F:→ LPH66: 所参照的变数是 ci, 这里是参照指定并没有解参照取值 06/20 03:11
12F:→ LPH66: 所以就算是顶层的常数性依然会保留 06/20 03:11
抱歉还是没办法理解,
假如:
const int i = 1;
const int *const j = &i;
const int *const k = j;
「但当我们 assign 值出来时, 我们是复制值」
k复制j的值,也就是取得j的记忆体存放的i位址。
「因此这最顶层变数参照被我们解参照了, 其常数性不再有意义」
请问j是在指派给*const k时被解参照吗?
不太懂什麽时候最顶层变数被解参照…
我可以理解成:
「只要A变数被指派给B变数,就是仅仅传递A的值给B,不会传递其余存在A变数上的特性,
而在B变数上,施加在A变数的种种特性都不会存在」吗?
不过这又回到了为什麽A变数的种种特性都不会在B变数上面存在的问题了...
13F:推 g0010726: 用个比喻来形容好了, 一个不能被涂改的书像是图书馆内 06/20 04:08
14F:→ g0010726: 的书(const Book), 你在copy後得到的新书究竟能不能被 06/20 04:08
15F:→ g0010726: 涂改你可以自己决定,跟原本的书没关系。但如果你有个 06/20 04:08
16F:→ g0010726: reference或pointer代表着(指向)图书馆的书,这个状况 06/20 04:08
17F:→ g0010726: 下const就该被保留,因为那本图书馆的书不该被涂改 06/20 04:08
没办法理解copy之後为什麽原本变数的一部分特性就消失...
※ 编辑: museangel (111.251.33.237 台湾), 06/20/2021 08:10:55
18F:→ sarafciel: const不是变数与生俱来的特性 const是一种契约 06/20 08:59
19F:→ sarafciel: 关於"某个特定位置上的某个值,我不会去改他"的契约 06/20 09:03
20F:→ sarafciel: 然後参考不是别名 参考是一种拷贝 只是他copy的东西是 06/20 09:17
21F:→ sarafciel: 位置 参考实际上是封装後的指标 而不是别名 06/20 09:18
22F:→ sarafciel: 你把问题想得太复杂了 实际上只是有没有可能改到那个ci 06/20 09:22
23F:→ sarafciel: 的值 所以这份契约要不要延续的问题 06/20 09:23
谢谢各位大师从各种不同角度说明,很开心终於理解了!
确实常数就是要限制特定变数的记忆体内的值不要被更动而已,
如果复制出去各自分离、互不干涉的,就不需要为新分出去的值加上不能更动的限制。
原本一直纠结在什麽顶层const、低层const,
没有意识到,只要结合设定常数的目的:「不让特定变数记忆体内的值更动」,
跟指派「是拷贝原本变数记忆体内的值」,
而由「拷贝出的值有无可能影响到常数变数记忆体内的值」,再去想就通了。
一、在基础型别的指派中:
每个变数的记忆体位址里面存有各自的值,
而const就是要保护被它套用的特定变数的记忆体位址内的值不被更改,
在拷贝过後,已经各自分离,
故新变数内的值无论怎麽更动都不会影响到常数变数记忆体内存放的值,
不用在新变数套上const。
二、在复合型别的指派中:
1.指向常数基础型别的常数或非常数指标:
如前述,因为拷贝後各自分离,
可不在意此处是否为常数指标,只要关注被指向的基础型别变数是否为常数,
而之所以还需要关注,是因为指标内存放的位址,
存有常数基础型别变数被限制不能更动的值,非其他被复制出去已各自独立的值。
2.参考常数基础型别的常数参考:
因为参考会更动到基础型别的记忆体内存放的值,(虽然不知道参考是怎麽封装的指标...)
因此在被参考之物件为常数基础型别时,就必须让参考同样是常数参考,
否则就会有可能更动到常数基础型别变数的记忆体内所存放的值。
※ 编辑: museangel (111.251.33.237 台湾), 06/20/2021 11:50:54
24F:推 howareuuu: 推比喻 06/21 08:24