免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: liaoweijun
打印 上一主题 下一主题

const总结 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2008-07-15 09:54 |只看该作者
补充一下,const是有传染性的

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
22 [报告]
发表于 2008-07-15 10:25 |只看该作者
原帖由 silverzi 于 2008-7-15 09:52 发表


有什么鸭子不鸭子的,优化就是优化,等价性证明出错什么鸭子都没用。
所以理解const的标准语义才是最重要的,编译器必须语义等价于它。


鸭子哲学的意思就是只要永远不露破绽,随你底下怎么玩
——这其实是“无论如何,编译器必须保持语义等价于标准定义”的俏皮说法^_^


如果等价性证明出错,那么就说明编译器优化出了bug,或者用户做了不正确的假设

比如,已知const int a=100,那么用const_cast去掉a的const属性后,这个a是不是就完全等价于变量?
答案就是:不清楚。看编译器想怎么玩了——一般来说,敢这么玩,都是要碰破头的。

——所以,在c++世界里,应该禁用c风格类型转换,改用语义明确的c++风格的xxx_cast<>
——不是说用c++风格类型转换就可以解决问题,而是c++风格转换语义明确、标志醒目,因而更难隐藏错误。


至于const的传染性,其实是另一个方面的东西。
我们前面讨论的从本质上说是“常量声明语义”;传染性其实是指它的“权限语义”(这个语义我前面说过)。

如: 有一个函数void x(const string& a),哪怕传给它的string a在外部是可改写的,到了x里面也不允许作半点改动。
这实质上是剥夺了x对传入参数的写权限;那么对于x调用的下级函数,它们显然也不应该修改a(或者说得到对a的更高的访问权限)——这就是所谓的“传染”。

借助这种机制,我们就可以防止外部string在x中被意外改写;这样,const &一方面保留了传统的传地址方式调用函数的速度优势,又可以像传值方式一样避免外部变量被意外改写。

[ 本帖最后由 shan_ghost 于 2008-7-15 10:34 编辑 ]

论坛徽章:
0
23 [报告]
发表于 2008-07-15 10:25 |只看该作者
我上面就一句话,可能难以理解,补充两个思路:

1〉最常见的,const_iterator引用的object能否访问非const修饰的函数?
2〉在类似上面的情况下,函数指针呢?

(呃,c思路类似)

[ 本帖最后由 silverzi 于 2008-7-15 10:29 编辑 ]

论坛徽章:
0
24 [报告]
发表于 2008-07-15 10:48 |只看该作者
支持,继续。

论坛徽章:
0
25 [报告]
发表于 2008-07-15 11:46 |只看该作者
原帖由 shan_ghost 于 2008-7-15 11:24 发表
...
吃透了这两点,其它变化就都逃不出你的掌握了。


前面我指针都说了,看来你没有真正了解const的隐患啊。

首先,编译器对const声明的对象的处理最起码要保证两点:
1〉传给成员函数的this是const Class类型的,即没有const声明的函数就无法使用
2〉成员变量全加上const

接下来,用const之前还要要意识到:编译器很难保证const实现的语义与你想要的等价。
如:

////////////////////////////////////////////
// 下面是手写的,如果编译无法通过勿怪

void g_func(char* c)
{ *c = 0; }

class A
{
public:
        void func() const
        { g_func(_s); }
       
private:
        char *_s;
};

main()
{
  const A a;
  a.func(); // 这里能通过编译,但用户关心的A的状态实际上已经改变了。类似容器拷贝的概念
}

/////////////////////////////////////////////

[ 本帖最后由 silverzi 于 2008-7-15 11:54 编辑 ]

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
26 [报告]
发表于 2008-07-15 12:10 |只看该作者
原帖由 silverzi 于 2008-7-15 11:46 发表


前面我指针都说了,看来你没有真正了解const的隐患啊。

首先,编译器对const声明的对象的处理最起码要保证两点:
1〉传给成员函数的this是const Class类型的,即没有const声明的函数就无法使用
2〉成员 ...


这里的char *_s;前要加muteable(好像这这样写的)关键字,否则class A是通不过编译的。


原因很简单,const A a指定对象a为const,那么任何能改变a的内部状态的调用都不被允许。
默认情况下,c++编译器认为所有的成员函数都会改变类内部状态,因而对a的任何方法的调用都会被阻止。

class A
{
public:
        void func() const

这个声明则告诉编译器,调用a.func()不会改变对象a的内部状态。

那么,究竟你有没有改变这个内部状态呢?编译器内部会自动检查你有没有修改任何a内部成员变量——这个修改包括把a._s传给可能修改它的外部函数。


但事实上,A内部成员并非完全不可改变——比如,假如a.func()需要设置A::m_error_msg呢?
这种修改不会影响A的行为;但它同样会被编译器阻止。

因此,c++专门为它准备了另一个关键字:muteable。
这个关键字告诉编译器:忽略const情况下对这个变量的修改——请闭嘴。


无论如何,const的两个基本性质都没有任何改变;只是在类场合里,为了精确实现这一点又不影响表达能力,c++不得不推出了更多的关键字。

[ 本帖最后由 shan_ghost 于 2008-7-15 12:11 编辑 ]

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
27 [报告]
发表于 2008-07-15 12:13 |只看该作者
不要质疑C++标准委员会那帮子大佬们的智慧——他们是不会那么容易留下漏洞的

论坛徽章:
0
28 [报告]
发表于 2008-07-15 12:24 |只看该作者
慢慢来,不习惯批量回内容……

原帖由 shan_ghost 于 2008-7-15 12:10 发表
这里的char *_s;前要加muteable(好像这这样写的)关键字,否则class A是通不过编译的。


对于这,我只能说,这代码是说明“指针所指的内容在不在和应不应该在const作用范围内”的伪码,别忽悠我。

[ 本帖最后由 silverzi 于 2008-7-15 12:26 编辑 ]

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
29 [报告]
发表于 2008-07-15 12:28 |只看该作者
其实,现在C++的最大问题不是标准有漏洞;而是为了支持太多东西,标准里被加入了太多的东西。


比如,引入一个const很简单,很容易,也很有用;但为了和类、和外部引用(extern)配合使用,又不得不引入“不修改类内部状态的成员函数的声明方法”、引入volatile;然后,这些新东西又带来了新的问题,于是又引入了muteable关键字……



这么多东西,如果不彻底理清了,一点一点搞明白,显然是会越搞越乱、越学越糊涂的。



比如,对const,基础其实就两点: 常量声明 和 权限控制。

这两点吃透后,就可以进一步接触“常量优化”;继而发现有时(多线程/外部引用等场合)常量优化会闯祸,于是学会用volatile关键字阻止这种优化。

同时,发现常量对象的成员函数无法调用,于是学会
class A
{
public:
        void func() const
这种写法。

再往后,发现需要修改A内部一个无关紧要的成员变量也会被编译器阻止,于是又找到了muteable……


这样学来,逻辑清晰,需要掌握的知识点少——甚至可以直接从各个关键字上望文生义出来,几乎不需要记忆任何内容。

相反,一上来就把所有这些东西列出几十条来,不学成糊涂蛋才怪。

论坛徽章:
0
30 [报告]
发表于 2008-07-15 13:13 |只看该作者
原帖由 shan_ghost 于 2008-7-15 12:39 发表


“指针所指的内容在不在和应不应该在const作用范围内”似乎应该直接了当比较:
const char * const p = "xxx";

const char * p = "xxx";
之类东东吧?


论坛就是想到什么就说什么,要考虑太多还不如去写论文。

言归正传,我指的问题就是上面你写的:

const只写了一次(const A),那么成员指针变量会被如何解释?
const char *
还是
char const*
还是
const char const *

上面的情况如果只解释成一种(应该是char const*),那么应用const A(一般由const_iterator引出)时就会产生二义性(我已举例)。

muteable能解决这些问题不?
如果不能,还有没有其它手段?

如果都不能,那么这个隐患就成立了。

[ 本帖最后由 silverzi 于 2008-7-15 13:26 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP