避免未定义行为(使用引用时的未定义行为)
一个变量在使用const_cast去掉指针或者引用的const限定符后,“如果常量本身不是常量,获得的权限是合法的, 如果本身是常量,使用const_cast再写的后果是未定义的。”

int main(){
    const int a = 1;
    int & b = const_cast<int&>(a);
    b = 2;
    cout << a ;
    cout << b;
}
1
2
3
4
5
6
7
虽然上面程序运行没有问题,但定义const常量的初衷肯定就是为了不修改,所以出现了上述情况肯定是程序设计有问题。

而且你会发现调试窗口中,两个变量的值按照我们所想,但打印时,却是先打印1,后打印2。这是因为常量折叠。

常量折叠
将上面代码进行反汇编。

const int a = 1;
00971F72 C7 45 F4 01 00 00 00 mov         dword ptr [a],1  
    int & b = const_cast<int&>(a);
00971F79 8D 45 F4             lea         eax,[a]     //可以发现,引用本质是指针,这里把a的地址先存到eax
00971F7C 89 45 E8             mov         dword ptr [b],eax   //再把地址赋值给b
    b = 2;
00971F7F 8B 45 E8             mov         eax,dword ptr [b]  //先把地址给eax
00971F82 C7 00 02 00 00 00    mov         dword ptr [eax],2    //中括号里面放的是地址
    cout << a ;
00971F88 8B F4                mov         esi,esp  
00971F8A 6A 01                push        1      //打印的时候,直接入栈的是1,这里发生了常量折叠
00971F8C 8B 0D D4 D0 97 00    mov         ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (097D0D4h)]  
00971F92 FF 15 E4 D0 97 00    call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (097D0E4h)]  
00971F98 3B F4                cmp         esi,esp  
00971F9A E8 0E F3 FF FF       call        __RTC_CheckEsp (09712ADh)  
    cout << b;
00971F9F 8B F4                mov         esi,esp  
00971FA1 8B 45 E8             mov         eax,dword ptr [b]  
00971FA4 8B 08                mov         ecx,dword ptr [eax]  
00971FA6 51                   push        ecx  
00971FA7 8B 0D D4 D0 97 00    mov         ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (097D0D4h)]  
00971FAD FF 15 E4 D0 97 00    call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (097D0E4h)]  
00971FB3 3B F4                cmp         esi,esp  
00971FB5 E8 F3 F2 FF FF       call        __RTC_CheckEsp (09712ADh) 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
常量折叠就是,在编译阶段,对该变量进行值替换。类似宏定义。

使用指针时的未定义行为
int main(){
    const int a = 1;
    int * b = const_cast<int*>(&a);
    *b = 2;
    cout << &a <<endl;
    cout << b << endl;
    cout << a << endl;
    cout << *b << endl;
}
1
2
3
4
5
6
7
8
9

使用const_cast去掉const限定符
只有当对象原本就是非常量时,才是正确的行为。

void func(const int& a)//形参为,引用指向const int
{
    int& b = const_cast<int&>(a);//去掉const限定,因为原本为非常量
    b++;
    return;
}

int main()
{
    int a = 100;
    func(a);
    cout << a << endl;  // 打印101
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
此函数的形参本来设置为int& a就好,但这里只是为了体现用法。

使用const_cast添加const限定符
const string& shorter(const string& s1, const string& s2) {
    return s1.size() <= s2.size() ? s1 : s2;
}

string& shorter(string& s1, string& s2) {
    //重载调用到上一个函数,它已经写好了比较的逻辑
    auto &r = shorter(const_cast<const string&>(s1), const_cast<const string&>(s2));
    //auto等号右边为引用,类型会忽略掉引用
    return const_cast<string&>(r);
}
1
2
3
4
5
6
7
8
9
10
const string&版本函数为比较字符串长度的正确实现,因为比较长度时不会改变字符串,所以参数和返回值都为const。
当实参为const时,由于函数重载,会调用到const string&版本函数,这也是期望的结果。

但当实参为非const时,我们希望还是继续调用已经写好比较逻辑的const string&版本函数,但返回值希望返回string &,所以这里再封装一层函数。(这里一个知识点,函数重载是忽略返回值,且忽略形参的顶层const,可以这么理解,有顶层const的概念,说明参数是引用或指针,但我们主要关心的是指向的数据,所以要忽略顶层const)(因为参数忽略顶层const,所以重载时只关心底层const是否一样)
————————————————
版权声明:本文为CSDN博主「anlian523」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/anlian523/article/details/95751762

const_cast的使用:添加或去掉const、常量折叠相关推荐

  1. C和C++里的const常量、volatile修饰符的深层次说明

    目录 一.写在前面 二.分析C和C++中const常量被修改后值的状态 2.1 C中const常量被修改后值的状态 2.2 C++中const常量被修改后值的状态 2.3 C和C++中const常量被 ...

  2. 编程语言中的常量折叠(const folding)

    深度学习框架theano的文档中说,theano支持const folding.在google上搜索const folding,提示更多的是一种编译器的编译优化技术.常量折叠(const foldin ...

  3. c语言 const常量作用,C语言 const常量讲解

    //const的本质 //const本质上是伪常量,无法用于数组初始化以及全局变量初始化 //原因在于const仅仅限定变量无法直接赋值,但是却可以通过指针间接赋值 //例如局部常量在栈区,而不在静态 ...

  4. const常量和readonly常量区别

    1.const常量为静态常量:readonly常量为动态常量: 2.const常量在编译时值被确定,在运行时值为编译时值:readonly常量,在编译时为类型的默认值(非指定的默认值),在运行时值被确 ...

  5. const常量与define宏定义的区别

    #define RADIUS 100; const  float   RADIUS = 100; (1) 编译器处理方式不同 define宏是在预处理阶段展开. const常量是编译运行阶段使用. ( ...

  6. C++ const常量和指针

    1 const int g_earth = 9.8; 2 const int * pe = &g_earth; //可行 3 4 const int g_moon = 1.3; 5 int * ...

  7. c语言const常量用法,C++ const常量在多文件编程中的3种用法

    <C++多文件编程是什么>一节提到,多文件编程中代码的划分原则是:将变量.函数或者类的声明部分存放在 .h 文件,对应的实现部分放在 .cpp 文件中.值得一提得是,此规律适用于大部分场景 ...

  8. c语言常量折叠,C/C++中const关键字相关

    const 本文根据<C和指针>3.4节,<C专家编程>1.9节以及相关网络资源整理总结const三个不易理解的地方: 声明,函数参数赋值,存储类型.如有偏误,欢迎指正,共同学 ...

  9. const常量函数详解

    在类中,如果你不希望某些数据被修改,可以使用const关键字加以限定.const 可以用来修饰成员变量和成员函数. const常量与指针 ` const int *p1与const int *p2的顺 ...

最新文章

  1. 分布式系统熔断机制的工作原理
  2. gitbook的使用
  3. 面试题 04.03. 特定深度节点链表
  4. 居中的最佳方法 div 在垂直和水平页面上? [重复]
  5. 【原创】开源Math.NET基础数学类库使用(03)C#解析Matlab的mat格式
  6. 有谁知道千千静听中的波形特效是怎么做的?
  7. CSS 3.0实现八卦图
  8. python应用——简单的跟随北上资金策略
  9. startx 命令详解
  10. Legacy与UEFI
  11. JAVA WEB DAY 16_ 综合案例-联系人管理系统
  12. CSS3 @Media 媒体查询
  13. iwebsec靶场搭建
  14. 电脑里的计算机无法打字,电脑键盘无法打字的原因及解决方案
  15. 用HTML创作一个简单的电子时钟
  16. 如何隐藏一个盘让其他人搜索不到
  17. 毫米波目标检测论文 阅读笔记 | Radar Transformer: An Object Classification Network Based on 4D MMW Imaging Radar
  18. linux u盘 命令,制作U盘版linux系统安装盘(DD命令)
  19. 3MX格式转OSGB格式
  20. Vue3发送验证码-防止页面刷新-发送验证码状态改变

热门文章

  1. data too long for column的解决方法
  2. php 中文 decode_php json_decode 解析中文
  3. iOS之深入解析对象isa的底层原理
  4. HarmonyOS之生物特征识别的功能和使用
  5. 计算机网络的拓扑结构主要取决于它的( )
  6. 1.4 第一个Python程序
  7. 数数塔 NBUT - 1083
  8. 【Linux】一步一步学Linux——dpkg-preconfigure命令(275)
  9. python字典进行大写转化_python之字典的增删改查
  10. java 自定义消息_Vc中自定义消息及其触发使用