C++编程思想 第1卷 第10章 名字控制 静态初始化的相依性 怎么办 技术二

与技术一相比,这种技术更简单,也更清晰

技术基于事实,函数内部的静态对象在函数第一次被调用时初始化,且只被
初始化一次

真正想解决的不是静态对象什么时候被初始化,而是确保正确的初始化顺序

技巧很灵巧 对于如何初始化依赖因素来说,可以把一个静态对象放在一个能
返回对象引用的函数中

两个互相依赖的类
第一个类包含一个bool类型的成员,它只由构造函数初始化,所以能够知道该
类的一个静态实例是否调用了工作方式

 

//: C10:Dependency1.h
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#ifndef DEPENDENCY1_H
#define DEPENDENCY1_H
#include <iostream>

class Dependency1 {
  bool init;
public:
  Dependency1() : init(true) {
    std::cout << "Dependency1 construction" 
              << std::endl;
  }
  void print() const {
    std::cout << "Dependency1 init: " 
              << init << std::endl;
  }
};
#endif // DEPENDENCY1_H ///:~

 

 

构造函数也显示它是什么时候被调用的,为了知道对象是否被初始化,可以
通过print()函数打印出对象的状态

第二个类初始化由第一个类的一个对象来完成,这会导致初始化相互依赖

 

//: C10:Dependency2.h
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#ifndef DEPENDENCY2_H
#define DEPENDENCY2_H
#include "Dependency1.h"

class Dependency2 {
  Dependency1 d1;
public:
  Dependency2(const Dependency1& dep1): d1(dep1){
    std::cout << "Dependency2 construction ";
    print();
  }
  void print() const { d1.print(); }
};
#endif // DEPENDENCY2_H ///:~

 

 

构造函数显示它自己并打印出对象dl的状态,所以能够知道当构造函数被
调用时,dl是否已经初始化了

为了说明会出现什么错误,下面的文件首先以一种不正确的顺序定义静态
对象,如果在对象Dependency之前连接器碰巧初始化对象Dependency2,错误
就会出现

为了有更多的可读性的输出,增加separator()函数内部的静态对象在函数第一次被调用时初始化,且只被

诀窍就是不能全局地调用一个函数,除非该函数用来执行一个变量的初始化
操作,所以separator()函数返回一个哑元值用来初始化两个全局变量

 

 

//: C10:Technique2.cpp
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#include "Dependency2.h"
using namespace std;

// Returns a value so it can be called as
// a global initializer:
int separator() {
  cout << "---------------------" << endl;
  return 1;
}

// Simulate the dependency problem:
extern Dependency1 dep1;
Dependency2 dep2(dep1);
Dependency1 dep1;
int x1 = separator();

// But if it happens in this order it works OK:
Dependency1 dep1b;
Dependency2 dep2b(dep1b);
int x2 = separator();

// Wrapping static objects in functions succeeds
Dependency1& d1() {
  static Dependency1 dep1;
  return dep1;
}

Dependency2& d2() {
  static Dependency2 dep2(d1());
  return dep2;
}

int main() {
  Dependency2& dep2 = d2();
  getchar();
} ///:~

 

函数d1()和d2()包含类Dependency1和Dependency2的静态对象

输出
Initializer()
performing initialization
Initializer()
Dependency2 construction Dependency1 init: 0
Dependency1 construction
---------------------
Dependency1 construction
Dependency2 construction Dependency1 init: 1
---------------------
Dependency1 construction
Dependency2 construction Dependency1 init: 1

使用技术二。
通常,静态对象在单独的文件中定义,而不是在单独的文件中定义一个包含
静态对象的函数。但是需要在头文件中声明

 

//: C10:Dependency1StatFun.h
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#ifndef DEPENDENCY1STATFUN_H
#define DEPENDENCY1STATFUN_H
#include "Dependency1.h"
extern Dependency1& d1();
#endif // DEPENDENCY1STATFUN_H ///:~

 

实际上,关键字 extern 对于函数声明来说是多余的

 

//: C10:Dependency2StatFun.h
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#ifndef DEPENDENCY2STATFUN_H
#define DEPENDENCY2STATFUN_H
#include "Dependency2.h"
extern Dependency2& d2();
#endif // DEPENDENCY2STATFUN_H ///:~

 

在前面的顺序文件中,有静态对象定义,现在,改为在包装的函数定义中
定义静态对象
 

//: C10:Dependency1StatFun.cpp {O}
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#include "Dependency1StatFun.h"
Dependency1& d1() {
  static Dependency1 dep1;
  return dep1;
} ///:~

 

其他的代码也可以放在这些头文件中,下面是另外一个文件

 

//: C10:Dependency2StatFun.cpp {O}
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#include "Dependency1StatFun.h"
#include "Dependency2StatFun.h"
Dependency2& d2() {
  static Dependency2 dep2(d1());
  return dep2;
} ///:~

 

现在有两个文件,这两个文件可以以任意的顺序连接
如果它们只包含普通的静态对象,那么可以产生任意顺序的初始化

在这里因为它们包含定义静态对象的函数,所以不会出现不正确的初始化

 

//: C10:Technique2b.cpp
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
//{L} Dependency1StatFun Dependency2StatFun
#include "Dependency2StatFun.h"
int main() { d2(); getchar();} ///:~

 

当运行这个程序时,将会发现Dependency1类的静态对象的初始化总是发生在
类Dependency2的静态对象的初始化之前

我们也许想在函数d1()和d2()的头文件中把它们声明为内联函数,但是我们
必须明确地知道这样做不行

输出
Initializer()
performing initialization
Initializer()
Dependency1 construction
Dependency2 construction Dependency1 init: 1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值