有时候我们会不给C++类成员变量赋初始值,或是因为忘记在构造函数中指定(C++11可以写在类内),或是觉得没有必要写。然而,因为觉得编译器会把变量赋成0而不写是错误的。本文通过C++标准来解释这个问题。

本文基于N3337(C++11草案)标准。

关于没有初始化器的对象,在8.5-11中有提及:

If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value.

没有初始化器的对象会被默认初始化;没有初始化的自动(局部变量)或动态存储期限(new出来的)对象的值是未定的。

这里涉及到了两种“无初始化”的概念,没有初始化器与没有初始化,注意区分。8.5-6对默认初始化(default-initialize)的定义是:

To default-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

  • if T is an array type, each element is default-initialized;

  • otherwise, no initialization is performed.

默认初始化T类型的对象是指:

  • 如果T是(可能有constvolatile的)类类型,T的默认构造函数会被调用(如果没有可用的,初始化就是非法的)(默认构造函数可能会对成员执行默认初始化);

  • 如果T是数组类型,每个元素被默认初始化(同样是递归的默认初始化);

  • 否则,不初始化。

从这些标准中的条款,可以得出结论:自动或动态存储期限的非类类型对象,无论是否是数组或是否有const修饰,如果不指定初始值,它的值就是未定的。

而整数类型、指针类型等都属于非类类型,如果我们希望这些类型的成员变量有确定的初始值,即使是看起来默认的0,也要自己写上初始化

----------------分割线----------------

我在这个问题上栽过大跟头,这就是我要写这篇文章的原因。

那是一个单片机的C++程序,涉及到一个二重指针数组,类型是一个定义了虚函数的基类,通过指针调用虚函数。数据结构并不复杂,逻辑肯定不会出错,但是程序跑飞了。

一开始觉得是初始化的问题,就把所有全局变量换成单例模式创建,无果。然后加了许多调试语句,把问题定位到了解引用上。想了想指针解引用肯定不会出问题,就觉得问题在虚函数调用过程中的函数指针解引用上。把指针调用(动态绑定)换成对象调用(静态绑定),果然程序就正常了。但函数指针解引用本质上是修改PC(程序计数器)寄存器,这种编译器搞定的事情我也插不了手。换了新版本的编译器,也没有解决。

后面的探索就奇怪了起来。我发现给PCB加一个100uF的电容可以让程序在烧写后正常运行,但在重新上电后,一旦程序去调用那虚函数,单片机就会复位;如果把业务逻辑改简单一点,有助于重新上电后正常工作,但没有本质上解决问题。用了一些猥琐操作后,我发现不是单片机复位而是程序回到起始处。这可能是未注册而触发的中断导致的,但就算给所有中断都指定了空函数,也还是没有解决。

百思不得其解,调试了一整天都没有成功。

几个月后再来看这个中断的项目,重新读了一遍代码,发现了这个初始值的问题,终于解决了。后面就很顺了。

现在看来这个debug的过程一开始方向挺对的,后面的探索就慢慢差到十万八千里外去了。

烧写正常运行、上电不正常的奇怪现象也可以解释了。单片机内置复位电路会在上电时给寄存器赋初值,但内存中的数据还是随机的。程序烧写前后内存中的数据被保留,之前的程序不知怎么把那一块内存初始化好了,烧写后就可以正常工作;而上电后那一块内存里都是随机值,对随机数进行4次解引用(二重指针2次,虚函数调用2次),程序早就不知道跑哪里去了。可能是寻到合法地址空间以外去了,由于某些保护机制的存在,程序就回到了起始处。

C++类成员默认初始值的更多相关文章

  1. C++ 变量默认初始值不确定(代码测试)

    C++ int变量默认初始值是不确定的,因此使用时初始化是很有必要的. 下面写个小程序测试一下int变量默认初始值. #include <iostream> #include <ve ...

  2. Java中在实例化一个类时,这个类中没有初始值的int类型成员变量i,i的值是不是0?

    java中有两种类型一种是数值性,另一种是类变量数值性变量的初始值为0,类变量的初始化为null没做初始化成员变量int性变量是0, 在java中有这么一条规则,声明在方法中的变量在使用时必须要初始化 ...

  3. Java语言基础(六)char成员变量默认初始值 最简单的Java源文件 Java的main()方法

    ①char成员变量的初始值是:'\u0000' ②package用来指定该文件所处的包的名称,必须位于源文件的顶端. import java.util.*; package com.hyy.test; ...

  4. 【C++】不要依赖编译器的默认初始值

    最好在定义的时候就给出初始值. 类和结构体给出构造函数. 比如int,在vs的debug和release模式下,初始化的值是不同的.

  5. Java未赋值变量的默认初始值

    在 Java 程序中,任何变量都必须经初始化后才能被使用.当一个对象被创建时,实例变量在分配内存空间时按程序员指定的初始化值赋值,否则系统将按下列默认值进行初始化: 数据类型 初始值 byte 0 s ...

  6. 【转】Lombok Pojo默认初始值问题

    Lombok以注解形式来简化java代码,提高开发效率.比如我们常用的@Builder.@Data.@AllArgsConstructor.@NoArgsConstructor.@ToString等. ...

  7. Lombok Pojo默认初始值问题

    Lombok以注解形式来简化java代码,提高开发效率.比如我们常用的@Builder.@Data.@AllArgsConstructor.@NoArgsConstructor.@ToString等. ...

  8. 126、Java面向对象之引用传递实例四,修改类成员的属性值

    01.代码如下: package TIANPAN; class Message { private String info = "此内容无用"; // 定义String类型属性 p ...

  9. Select2实现的带搜索的省市区三级联动代码 设置默认初始值

    $(function() { $('#loc_province').select2('val','2456'); $('#loc_province').change(); $('#loc_city') ...

随机推荐

  1. ubuntu server 1604 配置网络信息

    对于新安装的linux 服务器(ubuntu server 1604)   一,配置网络 连接网线与路由器 查看系统的网卡信息 ifconfig -a //列出所有的网卡信息,不管启用还是没有启用的 ...

  2. template screen

    从全局搜索主机可看到此screen

  3. MySQL双主+keepalived实现高可用实现(热备)

    环境:centos6.7 最小化安装 192.168.100.152 master 主192.168.100.153 slave 从192.168.100.132 v_ip 浮动IP 配置ssh密码登 ...

  4. 程序员的算法课(18)-常用的图算法:广度优先(BFS)

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...

  5. CCNA 之 六 路由协议 二 EIGRP

    EIGRP(Enhanced IGRP) 增强型内部网关路由协议 注意:这是cisco私有协议:也就是说,该协议只能运行在思科的设备上,如果有其他的厂家的设备,则不能保证能运行此协议: EIGRP的特 ...

  6. WebMagic 实现爬虫入门教程

    本示例实现某电影网站最新片源名称列表及详情页下载地址的抓取. webmagic是一个开源的Java垂直爬虫框架,目标是简化爬虫的开发流程,让开发者专注于逻辑功能的开发. WebMagic 特点: 完全 ...

  7. SpringBoot-运行原理(四)

    1.自动配置 (1).pom.xml 在pom文件中 <parent> <groupId>org.springframework.boot</groupId> &l ...

  8. luogu P1356 数列的整数性 |动态规划

    题目描述 对于任意一个整数数列,我们可以在每两个整数中间任意放一个符号'+'或'-',这样就可以构成一个表达式,也就可以计算出表达式的值.比如,现在有一个整数数列:17,5,-2,-15,那么就可以构 ...

  9. HihoCoder1466-后缀自动机六·重复旋律9

    小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段字符构成的字符串. 现在小Hi已经不满足于单单演奏了!他通过向一位造诣很高的前辈请教,通过几周时间学习了创作钢琴曲的基本理论, ...

  10. UVA-11107 Life Forms(求出现K次的子串,后缀数组+二分答案)

    题解: 题意: 输入n个DNA序列,你的任务是求出一个长度最大的字符串,使得它在超过一半的DNA序列中出现.如果有多解,按照字典序从小到大输入所有解. 把n个DNA序列拼在一起,中间用没有出现过的字符 ...