c ++ static-init-fiasco示例

use*_*854 2 c++ static-initialization

在Bruce Eckel的"Thinking in C++"的帮助下学习C++,坚持练习32,第10章.问题是如何更改链接顺序,Mirror :: test()调用对象m5返回false.这是我的代码.

mirror.h:

#ifndef MIRROR_H_
#define MIRROR_H_

class Mirror {
 public:
  Mirror() {logic_ = true; self_ = 0;};
  Mirror(Mirror *ptr) {self_ = ptr; logic_ = false;};
  bool test() {
    if (self_ != 0) {
      return self_->test();
    } else {
      return logic_;
    }
  };

 private:
  bool logic_;
  Mirror *self_;
};


#endif // MIRROR_H_
Run Code Online (Sandbox Code Playgroud)

任务

one.cpp

#include "mirror.h"
Mirror m1;
Run Code Online (Sandbox Code Playgroud)

two.cpp

#include "mirror.h"
extern Mirror m1;
Mirror m2 (&m1);
Run Code Online (Sandbox Code Playgroud)

three.cpp

#include "mirror.h"
extern Mirror m2;
Mirror m3 (&m2);
Run Code Online (Sandbox Code Playgroud)

等等.最后,

five.cpp

#include "mirror.h"

#include <iostream>

extern Mirror m4;
Mirror m5 (&m4);

int main(int argc, char* argv[]) {
  std::cout << m5.test() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

m5.test()返回true.任务说,我应该更改链接顺序,m5.test()返回false.我试过用:

init_priority(优先级)

在标准C++中,保证在命名空间范围内定义的对象按照严格按照给定转换单元中的定义的顺序进行初始化.不保证翻译单元的初始化.但是,GNU C++允许用户通过指定相对优先级来控制在命名空间范围内定义的对象的初始化顺序,相对优先级是一个当前限制在101和65535之间的常量整数表达式.数字越小表示优先级越高.

但没有运气.

完整的练习文字:

在头文件中,创建一个包含两个数据成员的类Mirror:指向Mirror对象和bool的指针.给它两个构造函数:默认构造函数将bool初始化为true,将Mirror指针初始化为零.第二个构造函数将一个指向Mirror对象的指针作为参数,它指向对象的内部指针; 它将bool设置为false.添加成员函数test():如果对象的指针非零,则返回通过指针调用的test()的值.如果指针为零,则返回bool.现在创建五个cpp文件,每个文件都包含镜像头.第一个cpp文件使用默认构造函数定义全局Mirror对象.第二个文件将第一个文件中的对象声明为extern,并使用第二个构造函数定义一个全局Mirror对象,并指向第一个对象.继续这样做,直到到达最后一个文件,该文件还将包含全局对象定义.在该文件中,main()应该调用test()函数并报告结果.如果结果为true,请找出如何更改链接器的链接顺序并更改它直到结果为false.

Die*_*ühl 5

将对象文件传递给链接器时,您需要更改它们的顺序.尽管不同的编译器使用不同的方法,即它不可移植,但这对于顶层代码是合理的.此外,对于库,您通常无法控制对象的包含顺序.例如,如果你有

// file1.cpp
int main() {
}

// file2.cpp
#include <iostream>
static bool value = std::cout << "file2.cpp\n";

// file3.cpp
#include <iostream>
static bool value = std::cout << "file3.cpp\n";
Run Code Online (Sandbox Code Playgroud)

...并链接两个这样的程序:

g++ -o tst1 file1.cpp file2.cpp file3.cpp
g++ -o tst2 file1.cpp file3.cpp file2.cpp
Run Code Online (Sandbox Code Playgroud)

你会得到不同的输出tst1tst2,例如:

$ ./tst1
file2.cpp
file3.cpp
$ ./tst2
file3.cpp
file2.cpp
Run Code Online (Sandbox Code Playgroud)

整体道德是:不要这样做.那就是:不要使用全局对象.如果您觉得绝对需要使用全局对象,请将它们封装到函数中,例如:

Type& global_value() {
    static Type value; // possibly with constructor arguments
    return value;
}
Run Code Online (Sandbox Code Playgroud)

这样,value在第一次访问时进行初始化,并且在未构造时无法访问它.如果你封装了这样的所有对象,你可以保证它们以适当的顺序构造(除非你有一个循环依赖,在这种情况下它不能工作,你应该认真重新考虑你的设计).不幸的是,上述将对象封装到函数中的方法在C++ 2003中并不是线程安全的.但是,它在C++ 2011中是线程安全的.尽管如此,使用全局变量通常是有问题的,你肯定希望尽量减少它们的使用.