[cpp primer随笔] 03.常量

1. 常量

const可以定义常量对象,这种对象一经定义,在程序运行期间无法被修改。也因此,常量对象必须初始化。

const int i = 0; // 常量
i = 5; // cannot assign to variable 'i' with 
       // const-qualified type 'const int'
       // 无法对具有const限定类型的变量'i'进行赋值操作

2. 常量表达式

const强调运行时对象的不可更改,也就是说你可以在运行时现定义一个const,而constexpr强调编译时确定结果。const无法像constexpr一样在编译阶段就对使用的地方进行替换,效率上有所不如,因此推荐将所有你认定为常量表达式的存在都用constexpr进行定义。

注意,常量和变量在c++里不是相对的概念。常量是指用const修饰,从而使其值无法更改的变量。

要定义常量表达式,首先要用const符修饰,其次要用另一个常量表达式对其进行初始化,可以是字面量,也可以是字面量的运算表达式。

int getsize(){
	return 20;
}
const int size = 20; // 常量表达式
const int size_1 = size + 1; // 常量表达式
const int size_2 = getsize(); // 不是常量表达式

2.1 constexpr关键字(C++ 11)

可以看到,虽然getsize函数返回值固定为20,但是size_2依旧无法被判定为常量表达式,这是因为编译器无法判定getsize的结果是否满足要求。这个时候,可以使用constexpr代替const来定义所有你认定为是常量表达式的符号。

constexpr int getsize(){
	return 20;
}
constexpr int size = 20; // 常量表达式
constexpr int size_2 = getsize(); // 常量表达式

需要注意三点:

  • 只有用constexpr修饰的函数,其返回值才能被用于给其他constexpr进行初始化。
  • 使用constexpr定义指针时,仅表明该指针是一个常量表达式,与其所指向对象无关。
  • 对于使用constexpr定义,但不符合常量表达式要求的情况,会产生编译时错误。例如:error: type name does not allow constexpr specifier to be specified。*

2.2 与const的区别

非常量表达式的const对象是变量,无法像constexpr一样在编译阶段就对使用的地方进行替换,效率上有所不如,因此推荐将所有你认定为常量表达式的存在都用constexpr进行定义。

下面写一段程序,并对其进行编译,加深理解。

constexpr int getsize(){
    return 20;
}

int getsize_2(){
    return 20;
}

constexpr int i = getsize_2();

void constexprTest(){
    int j = i;	// 使用非常量对象初始化
    int k = getsize(); // 使用常量表达式初始化
}

得到汇编代码如下:

constexprTest()     # @constexprTest()
# %bb.0:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     dword ptr [rbp - 4], 20 # 直接替换为20
        call    getsize_2() # 需要调用函数才能确定j的值
        mov     dword ptr [rbp - 8], eax
        add     rsp, 16
        pop     rbp
        ret         # -- End function

3. 常量对象的文件作用域

常量一般只在定义它的文件内有效。 要想在一个文件定义,在其他文件声明并使用它,可以使用extern关键字。

// a.cpp
extern const int size = 20;
// b.h
extern const int size; // 声明,与a.cpp是同一个常量对象

4. 常量引用

绑定到const对象上的引用,称之为常量引用( r e f e r e n c e reference reference t o to to c o n s t const const)。

const i = 0;
const &j = i; // reference to const

4.1 引用非常量对象

上面的例子里,我们创建了一个绑定到const对象进的引用。而常量引用还可以绑定非常量对象,与const对象相同,该引用无法在程序运行期间对绑定的对象进行更改。

int i = 20;
const int &j = i;
j = 21; // error: cannot assign to variable 'j' 
        // with const-qualified type 'const int &'

4.2 引用字面量

有趣的是,常量引用是可以引用字面量的,而非常量引用做不到这一点。

const int &i = 20; // 正确
int &j = 20; // error: non-const lvalue reference to type 
             // 'int' cannot bind to a temporary of type 'int'

下面写一段程序,并进行编译,来看下原理。

void constReference(){
    const int &i = 20;
}

汇编代码如下:

constReference():                    # @constReference()
# %bb.0:
        push    rbp
        mov     rbp, rsp
        mov     dword ptr [rbp - 12], 20 # 临时量对象
        lea     rax, [rbp - 12]
        mov     qword ptr [rbp - 8], rax # 对临时量对象进行引用
        pop     rbp
        ret                          # -- End function

可以看到程序先在栈空间上创建了一个临时量对象(没有命名的对象)20,再获取该临时量对象的地址以对其进行引用。

5. 指针常量与常量指针

这是个虽然基础,但是比较经典的知识点。但是我发现网络上对于此二者的解释和cpp primer上是相反的。这是翻译的问题,无关对错,我个人比较倾向于网上的说法。除此之外,我觉得与英文结合理解要清楚一点。

5.1 常量指针(pointer to const)

常量指针,即用于指向常量的指针。与无法使用非常量引用去绑定常量一样,要想存储常量对象地址,也必须使用具有所谓常量限定类型const-qulified的指针。

const int i = 5;
const int *p = &i; // 指针常量

const intint应视作两种不同的类型。因为指针类型与其指向对象类型必须相符,因此在用非常量对象的地址去初始化常量指针时,就会发生错误。

int i = 5;
const int *p = &i; // cannot initialize a variable of type 
                   // 'const int *' with an lvalue of type 'int'

5.2 指针常量(const pointer)

int i = 5;
int *const p = &i;

回想上一篇提过的就近原则,const限定符与变量名p最近,因此p首先是一个常量,再者是一个指向int类型对象的指针。常量类型使得该指针的值初始化后就无法改变,即无法指向其他对象。

上述二者也可以嵌套使用,例如:

const int i = 5;
const int *const p = &i;

此时,p是一个指向const int类型对象的指针常量。
此外,结合这种嵌套场景,cpp primer里面提出了两个名词,在之后会经常用到。

  • 顶层const:指针本身是常量。
  • 底层const:指针所指向的,或引用所绑定的,那个对象是常量。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++ Primer(第五版)》是一本深入浅出、权威全面的C++教程,并且非常适合初学者。这本书以系统的方式介绍了C++语言的基础知识,包括语法、数据类型、控制结构等。通过大量的实例和练习,读者能够更好地理解C++的概念和应用。 这本书的第五版是经过完全修订和更新的,以跟上C++11、C++14和C++17的最新标准。它包含了对新特性的详细解释,例如自动类型推导、lambda表达式、增强的类型检查等等。同时,书中还介绍了C++标准库和常用的编程技巧,如字符串处理、容器、迭代器等,以帮助读者更好地应用C++语言进行程序开发。 《C++ Primer(第五版)》的特点之一是它的逻辑性和结构性。每个章节都按照逐步深入的方式呈现,从基本概念开始,然后逐步引入更高级的内容。每个概念都配有大量的例子和实践题目,读者可以通过反复实践来巩固和加深对知识的理解。 此外,这本书还有一个非常有用的附录和索引,方便读者查找和理解C++语言中的各种概念和特性。 总的来说,如果你想系统学习和掌握C++编程语言,我强烈推荐你阅读《C++ Primer(第五版)》。它的全面性和权威性能够帮助你建立牢固的编程基础,并且对于学习其他高级主题和应用也提供了很好的引导。无论你是初学者还是有一定编程基础的人,这本书都能够帮助你进一步提升自己的C++编程能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值