- 主题:各cpp内用全局静态变量的构造函数来注册,踩坑了
static RegisterHelper<T> no_use;
构造函数使用了另一个头文件里的const 字符串,结果这个字符串此时还没初始化,——著名的“静态变量初始化顺序不确定”的问题。
以这种方式踩上了,意外意外,熟读EffectiveC++也得实战啊。
更新:
// 编译(链接)时初始化,Static Initalization阶段的 const initialization
const char* p = "hello";
// 加载时初始化,如果有多个静态变量依赖,就会顺序不定
const string s = "hello";
一 p是非局变量,生命周期为全程序(non local `static storage`),
这种变量在main之前初始化,分为两个初始化阶段:
1 Static initialization 静态初始化阶段,两种初始化方式:
1 优先 constant initialization
2 次先 zero-initialized
2 Dynamic initialization 动态初始化阶段
1 ...
2 ...
3 著名的顺序不定:同一文件(Translation Unit)按变量出现顺序;不同文件(Translation Unit)间顺序不定. `Static Initialization Ordre Fiasco`
二 符合 1.1 `constant initialization`,同时具备以下两个条件:
1 该变量有一个初始化器(`initializer`),—— 若没有,其默认初始化器能触发某类初始化动作也行.
2 变量非对象时,initializer的 full-expression 是 const-expression。此例中,full-expression 就是右边的 “hello”,是 const-expression.
变量是对象时,则要求对象调用 constexpr 的构造函数.
因此,指针是const initialization. 但换成string类,就到第二阶段了,动态初始化,就有了顺序不定的问题。
https://en.cppreference.com/w/cpp/language/initialization#Non-local_variables
https://en.cppreference.com/w/cpp/language/siof
--
修改:DoorWay FROM 124.114.151.*
FROM 61.185.194.*
const std::string 还是 const char *
【 在 DoorWay (DoorWay) 的大作中提到: 】
: static RegisterHelper<T> no_use;
:
: 构造函数使用了另一个头文件里的const 字符串,结果这个字符串此时还没初始化,——著名的“静态变量初始化顺序不确定”的问题。
:
--
FROM 183.179.53.*
前,有构造函数
后者没问题,昨天下班了。一会去公司再试试。
【 在 fanci 的大作中提到: 】
: const std::string 还是 const char *
--
FROM 61.185.159.*
前 图的什么?
【 在 DoorWay 的大作中提到: 】
: 前,有构造函数
: 后者没问题,昨天下班了。一会去公司再试试。
--
FROM 167.220.232.*
所以还是弄个 RegisterHelper<T>::instance() 函数会好一点。单例模式在 c++ 里面确实有用。
【 在 DoorWay 的大作中提到: 】
: static RegisterHelper<T> no_use;
: 构造函数使用了另一个头文件里的const 字符串,结果这个字符串此时还没初始化,——著名的“静态变量初始化顺序不确定”的问题。
: 以这种方式踩上了,意外意外,熟读EffectiveC++也得实战啊。
: ...................
--
FROM 110.81.1.*
三分无意,
三分应用层API都是传String类,平台层API是指针;这些常量主要是应用层用;
三分讨厌C,(指针、位运算、宏、0长数组……)
【 在 mango7788 的大作中提到: 】
: 前 图的什么?
--
FROM 124.114.151.*
症结不在单例,是声明变量、或者调用instance的地方,是non-local的,
这个运行时机不能保证里面用的字符串初始化好了。
这种模式在需要大量注册handler时,经常用到。我这个bug是在注册的过程中,访问了静态字符串。以前没意识到这问题,是机械的,认为在同行业的代码库中看到过都这样做,就没问题。只知其一,不知其二。
在dll加载后开始执行处,专门加个函数,DoRegister,里面逐个调用就不会有这问题。但是多个人要改同一个文件。
【 在 hgoldfish 的大作中提到: 】
: 所以还是弄个 RegisterHelper<T>::instance() 函数会好一点。单例模式在 c++ 里面确实有用。
:
--
修改:DoorWay FROM 124.114.151.*
FROM 124.114.151.*
受教了
【 在 DoorWay 的大作中提到: 】
: 三分无意,
: 三分应用层API都是传String类,平台层API是指针;这些常量主要是应用层用;
: 三分讨厌C,(指针、位运算、宏、0长数组……)
--
FROM 167.220.232.*
C++ super FAQ里对static initialization order fiasco有比较清楚的说明,而且讨论了几种idiom的优劣。
std::cin、std::cout本身的实现用的计数那种idiom
https://isocpp.org/wiki/faq/ctors#static-init-order
https://modernescpp.com/index.php/c-20-static-initialization-order-fiasco
--
FROM 222.131.206.*
对于大量定义字符串常量,有没有idiom?
是不是使用char * ,就到头了?
【 在 z16166 的大作中提到: 】
: C++ super FAQ里对static initialization order fiasco有比较清楚的说明,而且讨论了几种idiom的优劣。
: std::cin、std::cout本身的实现用的计数那种idiom
:
https://isocpp.org/wiki/faq/ctors#static-init-order: ...................
--
FROM 61.185.187.*