C++中{}初始化指针Book* book{}的对象构造逻辑是什么
核心结论
两种写法的行为完全不同,Book* book{} 不会创建任何Book类实例,这是测试结果出现差异的根本原因。
两种写法的底层逻辑
Book* book = new Book()执行时会完成三个动作:- 在堆区申请对应Book对象大小的内存空间
- 调用Book的默认构造函数在该内存上构造对象,每执行一次构造,静态成员
ID就自增1 - 把构造好的对象的内存地址赋值给栈上的指针变量
book
第一段测试循环10次,每次都执行new操作,ID会从初始值0逐次增长到10,自然出现5次ID<5、5次ID>5的输出,和观测结果一致。
Book* book{}执行时仅会在栈上创建一个Book*类型的指针变量,按照C++值初始化规则,没有显式赋初值的指针会被初始化为空指针nullptr。整个过程既不会申请Book对象的内存,也不会调用Book类的构造函数,静态成员ID会一直保持初始值0,不会发生变化。
空指针调用成员函数不崩溃的原因
第二段代码中book->GetID()能正常运行属于未定义行为的巧合:
C++中非虚成员函数的调用不会依赖对象地址做虚表跳转,编译器会将成员函数编译为独立的全局函数,调用时隐式把对象地址作为this指针传入函数。你写的GetID()函数全程只访问属于类本身的静态成员ID,根本没有解引用this指针去访问实例的非静态成员,哪怕传入的this是空指针,也不会触发非法内存访问,才会造成"指针有效、对象正常构造"的错觉。
你可以通过一个简单的测试验证这个逻辑:给Book类添加一个非静态成员变量,在GetID()中尝试读取这个成员的值,再运行第二段代码就会立刻触发空指针访问错误。
这也解释了第二段代码的输出:循环10次没有调用过一次Book构造函数,ID始终为0,永远满足小于5的判断条件,因此所有输出都是ID<5。
内容的提问来源于stack exchange,提问作者Luna Wolf
相关产品推荐
相关产品推荐

