在运行时,std库何时完全初始化,以便在不破坏代码的情况下使用它?

时间:2018-06-05 10:34:17

标签: c++ gcc std libc static-initialization

我正在开发一个项目,其中包含调用main之前的启动代码。然而,我并不知道std库的初始化。

我知道以下代码会引发分段错误。

#include <iostream>

void foo(void) __attribute__((constructor));
void foo() {
  std::cout << "foo" << std::endl;
}

int main() {
  std::cout << "Simple program to throw a segmentation fault" << std::endl;
}

通过使用std::ios_base::Init mInitializer;强制初始化ostream缓冲区(不确定它是否完全是ostream),可以使上面的代码工作。这意味着此时std库尚未完全初始化(这是我对上述示例的推断)。

那么什么时候才能使用std函数而不会破坏代码呢?有没有办法强制初始化完整的std库?

1 个答案:

答案 0 :(得分:2)

documentation for the constructor attribute说:

  

但是,目前,调用具有静态存储持续时间的C ++对象的构造函数和用属性constructor修饰的函数的顺序是未指定的。

这意味着ELF构造函数和静态对象(用于初始化std::cout)不能很好地混合。

另一方面,std::cout是一个历史异常,因为它依赖于C ++标准库中的构造函数。在ELF系统上,ELF构造函数以拓扑顺序运行。这意味着动态链接器会查看库依赖项(DT_NEEDED条目),并在初始化它们的依赖项之前延迟库的初始化。

因此,当ELF构造函数运行并构造应用程序定义的全局对象时,C ++代码可以假定C ++运行时库已完全初始化。唯一的例外是C ++库,它抢占了标准C ++标准库本身使用的例程(通过ELF符号插入),并且如果库之间存在循环依赖关系,那么就没有正确的初始化顺序。这两种情况都不常见,除非您编写自定义malloc或类似内容,否则可以通过适当的应用程序设计来避免。