rapidjson修改某个成员的值_C++|变量、对象、对象成员初始化的一些细节

本文详细介绍了变量初始化的重要性,特别是在C++中的应用场景。未初始化的变量可能导致不可预料的错误,而引用、const常量和对象必须在声明时初始化。此外,构造函数在对象初始化中的作用被强调,特别是对于含有常量或引用成员的类。静态成员和const数据成员的初始化有特殊要求,不能在构造函数中进行。文章还讨论了内存单元的表示和内存管理,指出编译器对全局和静态变量的自动初始化行为。
摘要由CSDN通过智能技术生成

变量初始化是指变量定义后的第一次赋值(声明、定义、赋值三者同时进行),此后的赋值一般称为数据的更新或修改(注意任何操作都是有时间成本的)。

任何变量不管有没有初始化或赋值,都会有一个随机值或垃圾值。

我们知道,世间万物都可以数据化表示,进一步可以比特化表示 ,也就是用一串串0100110010101001……来表示,而0、1的硬件实现就是一个用作开关的晶体管。

1ae5379591b231fbeedf615d2cef0317.png

每一个0或1称为一个比特(bit,对应一个开关晶体管),8个比特是一个字节(byte,),称为一个内存单元(字节是最小的内存单位),内存单元在内存中线性顺序排列,可以随机访问。在C++中,一个字母就用一个字节来表示,数字可以用4或8个字节来表示。通过数据类型的定义和类型的声明,编译器知道需要从哪个内存单元(变量名对应内存地址)开始访问,访问到哪个位置(内存单元)结束(C中没有定义字符串,以'0'标志结尾,磁盘文件以EOF标识)。

即使变量没有初始化,变量对应的地址值仍然对应一个内存单元,对应一串比特,这一串比特的值是不确定的、随机的,可以称为垃圾值。这些垃圾值不是程序员所期望的,所以未初始化的变量使用(在右值中引用)时会有不可预料的错误,所以编译器对部分数据类型有强制化要求初始化或默认初始化的行为。

对于指针,如果未初始化,其随机值不确定,也就是需要指向的内存单元不确定,更会引发不可预料的错误。

1 未初始化的变量在右值引用时会出现错误

int j;//此时未初始化,j为一随机值或垃圾值

int i = 0;

i = j+1;//未初始化的在右值中引用会引发错误

cout<

如果是指针未初始化直接引用,程序会直接崩掉,因为指向找不到内存单元地址。

2 强制要求初始化的部分

2.1 引用要求声明时必须同时初始化;

2.2 const常量(基本类型变量或对象)也必须在声明时同时初始化(对const对象只能调用const成员函数),因为是常量,不存在赋值更新,唯一的机会就是初始化时给定一个值。

3 建议初始化的部分

指针建议声明时初始化,或最近位置初始化;

4 编译器会自动初始化的部分

编译器会自动初始化未初始化的全局或静态变量;

5 局部变量为什么编译器不自动初始化

效率的考量,因为变量的赋值也是需要时间的;

6 数组的初始化

声明数组的同时可以对数组初始化:

float x[5] = { -1.1, 0.2, 33.0, 4.4, 5.05 };

初始化表的长度短于要被初始化的数组元素数目,那么剩余元素被初始化为0。

带有初始化的一维数组可以不定义长度:

int a[]={1,2,3,4,5}; //则默认数组大小为5

初始化可以使用上述的集合赋值,但初始化后需要再次修改时却不能再次使用这种集合操作。因为你无法再次用x做右值,因为x相当于一个指针常量,你如果使用x[i]做左值,此时的x[i]只是其中的一个元素而已:

float fn=1.1;

float x[5] = { -1.1, 0.2, 33.0, 4.4, 5.05 };

float y[] ={1.0,2,3,4,5};

//x = y; //错误,因为x不能做左值,它相当于一个指针变量

x[5] = 3.3; //溢出错误,因为元素序列从0开始,只有5-1个元素,

cout<

7 对象的初始化

对象的初始化使用一种特殊的成员函数,也就是构造(constructor)函数,通过构造函数为对象分配空间,进行初始化。

当程序员没有定义并实现构造函数时,编译器会调用一个默认的构造函数。

类的设计者在定义一个类时如果没有定义任何成员函数,也会有默认的四个函数:默认的构造函数、默认的复制构造函数、析构函数和赋值运算符重载函数。

构造函数可以重载,让对象有多种初始化形式。

当数据成员不是普通的内置类型,而是某一个类的对象(数据成员是类对象的情形成为数据聚合),可能无法直接用赋值语句在构造函数体中为它赋初值,程序员要显式声明并定义一个构造函数。

构造函数还有一个与普通函数不同的地方,就是可以包含一个构造函数初始化列表。

构造函数初始化列表位于函数头和函数体之间。它以一个冒号开头,接着是一个以逗号分隔的数据成员列表。

每个数据成员的后面跟着一个放在圆括号中的对应于该数据成员的构造函数的实际参数表。

如IntArray的构造函数可写为

IntArray :: IntArray(int lh, int rh): low(lh), high(rh)//low、high是成员,lh、rh是对应的值

{ storage = new int [high - low + 1]; }

显然利用初始化列表可以提高构造函数的效率。在初始化的时候,同时完成了赋初始的工作。

有二种情况必须用初始化列表。

I 是数据成员中含有一些不能用赋值操作进行赋值的数据成员,例如常量、引用数据成员,或对象数据成员,这时必须在初始化列表中调用数据成员所属类型的构造函数来构造它们。

II 派生类在构造函数中要对自身成员初始化,也要对继承过来的基类成员进行初始化,当基类没有默认构造函数的时候,通过在派生类的构造函数初始化列表中调用基类的构造函数实现。

8 不能在类声明中初始化const数据成员

const数据成员的初始化只能在类构造函数的初始化表中进行,不能在构造函数中对他赋值。

常量的数据成员指得是那些在对象生成时给定了初值,在整个对象的生命周期中,该数据成员的值是不能变的。常量数据成员的值必须在构造函数的初始化列表中进行初始化。

class A

{

A(int size);//构造函数

const int SIZE;

}

A::A(int size) : SIZE(size)//构造函数的初始化表

{…}

A a(100);//对象a的SIZE的值为100

A b(200);//对象b的SIZE的值为200

9 不能在类的构造函数中声明静态成员数据

静态成员变量的初始化不能放在类的构造函数中。

为静态成员分配空间称为静态成员的定义,静态成员的定义一般出现在类的实现文件中。如在SavingAccount类的实现文件中,必须要如下的定义:

double SavingAccount::rate = 0.05;

该定义为rate分配了空间,并给它赋了一个初值0.05。

如果没有这个定义,连接器会报告一个错误。

静态成员数据只能用静态成员函数来访问。静态的常量数据成员是整个类所有对象共享的一个常量。对整个类而言,不管定义了多少个对象,该成员永远只有一份拷贝。静态常量数据成员的值是在定义类时给定。

-End-

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值