iOS中C++静态全局变量的动态初始化时序

简介: 一个由于C++初始化失败导致Realm初始化失败的Crash

日志

+ (void)load
{
    [RLMRealm defaultRealm];
}
// Global realm state
static std::mutex& s_realmCacheMutex = *new std::mutex();

......

RLMRealm *RLMGetThreadLocalCachedRealmForPath(std::string const& path) {
    std::lock_guard<std::mutex> lock(s_realmCacheMutex);  // <--- Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)
    return [s_realmsPerPath[path] objectForKey:(__bridge id)pthread_self()];
}

最终的报错位置在这里,可以看出s_realmCacheMutex是一个空对象,能看出是初始化出了问题。

可是为什么没有初始化成功呢?

C++的静态初始化与动态初始化

  1. static initialization: 静态初始化指的是用常量来对变量进行初始化,主要包括 zero initialization 和 const initialization,静态初始化在程序加载的过程中完成,对简单类型(内建类型,POD等)来说,从具体实现上看,zero initialization 的变量会被保存在 bss 段,const initialization 的变量则放在 data 段内,程序加载即可完成初始化,这和 c 语言里的全局变量初始化基本是一致的。
  2. dynamic initialization:动态初始化主要是指需要经过函数调用才能完成的初始化,比如说:int a = foo(),或者是复杂类型(类)的初始化(需要调用构造函数)等。这些变量的初始化会在 main 函数执行前由运行时调用相应的代码从而得以进行(函数内的 static 变量除外)。

需要明确的是:静态初始化执行先于动态初始化! 只有当所有静态初始化执行完毕,动态初始化才会执行。

Objective-C的静态库与动态库

静态库与动态库的区别在于:

一、静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。

二、动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。

如果你在CocoaPods中使用了use_frameworks!,则Pods会将依赖库都打包成动态库

加载时序

静态库 + (void)load -> C++静态全局变量的动态初始化 -> 动态库 + (void)load -> main()

原因

不少人应该都猜出原因了吧,正是由于我在静态库的Load中初始化了Realm,导致Realm在获取互斥锁的时候出现了初始化失败。

解决方案

  1. 在+ (void)load中添加一个GCD异步任务,在异步中初始化Realm,此时GCD会将任务推迟到main之后执行。
  2. 改用动态库。
  3. 将Realm初始化延后。

参考资料

c++ 全局变量初始化的一点总结

目录
相关文章
|
2月前
|
编译器 C语言 C++
C++一分钟之-C++11新特性:初始化列表
【6月更文挑战第21天】C++11的初始化列表增强语言表现力,简化对象构造,特别是在处理容器和数组时。它允许直接初始化成员变量,提升代码清晰度和性能。使用时要注意无默认构造函数可能导致编译错误,成员初始化顺序应与声明顺序一致,且在重载构造函数时避免歧义。利用编译器警告能帮助避免陷阱。初始化列表是高效编程的关键,但需谨慎使用。
40 2
|
3月前
|
存储 C++
C++程序全局变量:理解与应用
C++程序全局变量:理解与应用
47 0
|
4天前
|
Dart API 开发工具
Dart ffi 使用问题之Dart API要在C++中使用,该如何初始化
Dart ffi 使用问题之Dart API要在C++中使用,该如何初始化
|
2月前
|
安全 C++ 开发者
C++一分钟之-RAII资源获取即初始化
【6月更文挑战第24天】RAII是C++中一种关键的资源管理技术,它利用对象生命周期自动获取和释放资源,减少内存泄漏。通过构造函数获取资源,析构函数释放资源,确保异常安全。优势包括自动性、异常安全和代码清晰。使用智能指针如`std::unique_ptr`和`std::shared_ptr`,以及标准库容器,可以避免手动管理。自定义RAII类适用于非内存资源。代码示例展示了智能指针和自定义RAII类如何工作。掌握RAII能提升程序的可靠性和可维护性。
32 6
|
1月前
|
编译器 程序员 C++
【C++高阶】掌握C++多态:探索代码的动态之美
【C++高阶】掌握C++多态:探索代码的动态之美
27 0
|
1月前
|
编译器 C++
【C++】详解初始化列表,隐式类型转化,类静态成员,友元
【C++】详解初始化列表,隐式类型转化,类静态成员,友元
|
2月前
|
存储 编译器 C++
【C++】类和对象④(再谈构造函数:初始化列表,隐式类型转换,缺省值
C++中的隐式类型转换在变量赋值和函数调用中常见,如`double`转`int`。取引用时,须用`const`以防修改临时变量,如`const int& b = a;`。类可以有隐式单参构造,使`A aa2 = 1;`合法,但`explicit`关键字可阻止这种转换。C++11起,成员变量可设默认值,如`int _b1 = 1;`。博客探讨构造函数、初始化列表及编译器优化,关注更多C++特性。
|
2月前
|
容器
C++11 列表初始化(initializer_list),pair
C++11 列表初始化(initializer_list),pair
|
3月前
|
编译器 C语言 C++
从C语言到C++⑦(第二章_类和对象_下篇)初始化列表+explicit+static成员+友元+内部类+匿名对象(上)
从C语言到C++⑦(第二章_类和对象_下篇)初始化列表+explicit+static成员+友元+内部类+匿名对象
26 1
|
3月前
|
C++ 开发者
C++程序中利用虚函数实现动态多态性
C++程序中利用虚函数实现动态多态性
33 2

热门文章

最新文章