2.const和constexpr

const

  • const修饰的变量,不能对其进行赋值操作
  • 但是,可以通过访问const对象的内存,对其进行修改

  • 分析下面代码
    int main(){
    
        const int data = 10;
        int *p = const_cast<int*>(&data);
        *p = 20;
        
        std::cout << data << std::endl;			//10
        std::cout << *(&data) << std::endl;		//20
        
        return 0;
    }
    
  • 以常量表达式初始化的const对象,编译器会将其出现的位置以其值替换
  • 所以上面的代码,通过访问data的内存对其进行修改,但输出data还是10;但其内存中的值确实被修改了

  • 分析下面代码
    	int main(){
    
    	    int val = 10;
    	    const int data = val;
    	    int *p = const_cast<int*>(&data);
    	    *p = 20;
    	    
    	    std::cout << data << std::endl;			//20
    	    std::cout << *(&data) << std::endl;		//20
    
        return 0;
    }
    
  • data并非以常量表达式初始化,其初始值不能在编译器获取,所以编译器不会对其进行优化处理
  • 所以const对象,不应该以任何理由被修改,很可能因为编译器的优化,产生莫名其妙的bug

  • 默认情况下,const对象只在当前文件类有效
  • 为了使得其能在多文件共享,其在定义时也需要加上extern关键字
    /*file_1.cc*/
    extern const int data = 10;
    
    /*file_2.cc*/
    extern int data;
    int main(){
    	
    	std::cout << data << std::endl;	//10
    	return 0;
    }
    

constexpr

修饰变量
  • constexpr修饰的变量,其必须以常量表达式初始化,且其具有const属性
    /*file_1.cc*/
    int val = 10;
    constexpr int data = val;	//error 表达式必须含有常量值
    
    /*file_2.cc*/
    const int val = 10;
    constexpr int data = val;	//正确,编译器优化将val替换为10
    
    /*file_3.cc*/
    int num = 10;
    const int val = num;
    constexpr int data = val;	//error	val并非以常量表达式初始化,所以其不能作为常量表达式
    
  • constexpr修饰指针变量时,其只能作为顶层const,且不能直接放在标识符前;同样的,其初始值必须是编译期可确定
  • 如全局变量、静态变量、函数地址等,其地址属于编译期可确定的
    int global = 10;
    
    int main(){
    	
    	static int static_val = 10;
    	//均正常编译
    	constexpr int *p_1 = &global;
    	constexpr int *p_2 = &static_val;
    	return 0;
    }
    

修饰函数
  • constexpr修饰的函数,隐式被指定为inline1

  • constexpr修饰的函数,只有当遵循以下两点时,其才能作为常量表达式使用

    • 传入的实参和返回值都是常量表达式;其返回值类型可以是void,只要不被当作常量表达式使用,就不会报错
    • 有且只有一个return
    constexpr int func(int arg){
        int tmp = arg*arg;
        for(int i=0;i<5;i++)
            tmp *= arg;
        return tmp;
    }
    
    int main(){
    
        constexpr int data = func(10);
        std::cout << data;	//10000000
        return 0;
    }
    

    上面的情况,因为func比较简单,所以其被折叠,可以作为常量表达式

    但在下面这种情况,就不行了;非常不讲武德

    constexpr int func(int arg){
        int ret = arg;
        for(int i=0;i<10000;i++)
            for(int j=0;j<1000;j++)
                for(int k=0;k<100;k++)
                    for(int l=0;l<10;l++)
                        ret++;
        return ret;
    }
    
    int main(){
    
        constexpr int data = func(10);	//error 评估操作次数超过上限
        std::cout << data;
        return 0;
    }
    
  • constexpr中定义的变量,无论其类型,必须初始化;但这并不意味着constexpr中的变量具有const属性

    这里就不上测试代码了,各位hxd自行实验


结语

  • constconstexpr细节较多,本文只做简述
  • 有任何错误评论区指正,共同进步

  1. inline只表示告诉编译器此函数可以被优化,并非让编译器优化 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值