effective c++ 20 使用对象前先初始化

  1. 内置类型
    C++中的内置基本类型,比如int,double,float等,初值都是垃圾值,即声明int i,i的初值是一个垃圾值。本书建议的最佳处理方法是:永远在使用对象之前将之初始化。比如:
 int x = 0;

const char* test = “hello world”;

double d; cin >> d;
  1. STL
    C++提供了丰富的容器,比如vector,list,deque,map和set等,这些容器已经写好了构造函数,所以总会自动初始化成默认值,程序员可以直接使用,比如:
vector<int> vt; vt.push_back(3);
  1. 自定义类
    C++在类中有专门初始化成员变量的构造函数,程序员可以写出合适的构造函数,比如:
class A
{
  private:
           int a;
          double b;
          string text;
  
  public:
         A():a(0), b(0), text("hello world"){} //构造函数
};

当声明

A obj;

时,obj的成员变量a,b和text就已经获得了初值,分别是0,0和hello world。

这里注意一下,有些C++的初学者喜欢这样写:

class A
 {
 private:
           int a;
           double b;
           string text;
  
  public:
          A()
         {
                   a = 0;
                    b = 0;
                   text = "hello world";
         }

 };

效果虽然和上一个例子一样,都获得了指定的初值,但执行的效率却不如上个例子。上一个例子中使用了成员初始化列表的方式,即在冒号后面逐一初始化,但本例却在函数体内进行了初始化。事实上,本例其实不能严格称为“初始化”,因为在进入构造函数的函数体时,这些成员变量已经被初始化了,a和b初始化成垃圾值,string因为是STL,调用默认的构造函数初始化为空字符串,在函数体内进行的操作实为“赋值”,也就是用新值覆盖旧值。这也正是说它的执行效率不高的原因,既进行了初始化,又在之后进行了赋值,不像上一个例子,只有初始化,一步到位。在有些特殊情况下,比如成员变量是const的或者是reference的,进行初始化后值就不可以改变了,这时只能用初始化列表,不能在函数体内赋值。
所以,应该尽可能地采用有冒号的成员初始化列表。注意这里的用词“尽可能地”,表示也不是所有情况都用这个初始化列表,当想构造的内容复杂,或者已经模块化为函数了,这时不能用初始化列表的方式,就采用在函数体内赋值的方式为好。

这里还有一个问题要注意下,当使用初始化列表时,初始成员变量的顺序与列表排列的顺序没有关系,只取决于声明这些成员变量的顺序,还是那个例子,将之改成:

class A
{
private:
      int a;
      double b;
      string text;

public:
       A():b(0), a(0), text("hello world"){}
};

虽然初始化列表的顺序是b在先,但编译器只会根据声明变量时的先后顺序,所以还是a被先初始化,想要用以下这种方式初始化的同学要当心:

class A
{
private:
         int a;
         double b;
         string text;

public:
         A():b(0), a(b), text("hello world"){}

};

这一定不会得到你想要的结果的,因为a会首先初始化,而这时b尚未初始化,所以会有bug。本书中建议,为了避免这种顺序不一致的晦涩错误,“当你在成员初值列中条列各个成员时,最好总是以声明次序为次序”。
4. 不同编译单元内定义的non-local static 对象
这里先解释一下名词,static是静态的意思,表示这个变量不由栈分配,而存储在特有的全局变量/静态变量区域中,具有长寿命的特点(从被构造出来,直到程序结束时,才会由系统释放资源);而non-local则是说这个对象是全局的,而不是函数内的静态变量,是说它的作用范围广。本博客中

http://www.cnblogs.com/jerry19880126/archive/2012/12/22/2829394.html

介绍了有关函数作域和生存周期的区别。

比如在文件1中定义了
int a = 1;
而在文件2中又会去使用:
extern int a;
int b = a *3;
可以看到文件1应在文件2之前执行,这样a才能获得初值,否则b得到的将是垃圾值,但事实上C++对于不同文件执行的相对次序并无明确定义,这样b究竟得到的是垃圾值还是3就不能确定。

解决这个问题是方法是不要使变量有全局的作用域,可以在文件1中定义:

int& GetA()
 {
          static int a = 1;
         return a;
 }

而在文件2中调用

int b = GetA();
这样就一定保证a的初始化在先了。
总结一下:

(1) 为内置型对象进行手工初始化,因为C++不保证初始化它们;

(2) 构造函数最好使用成员初始化列表(实际初始化顺序不与列表的排列顺序有关,只取决于类中的声明顺序),而不要在构造函数体内使用赋值操作;

(3) 未避免“跨编译单元的初始化次序”问题,请用local static代替non-local static对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发如雪-ty

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值