C++ seg错误,用于访问类似单例的静态成员

C++ seg错误,用于访问类似单例的静态成员,c++,C++,这是代码,简化了 //A class used in the next class, Nothing much to worry about class BasicLogger{ //... }; 下面是我的主课。它有两个您需要查看的成员:它自己类型的静态成员(称为log)。 以及一个容器(称为repo),用于容纳上述类别的对象回购的项目可通过操作员[]访问过载: class Logger { protected: // repository of profilers. each p

这是代码,简化了

//A class used in the next class, Nothing much to worry about
class BasicLogger{
//...
};
下面是我的主课。它有两个您需要查看的成员:它自己类型的静态成员(称为
log
)。 以及一个容器(称为
repo
),用于容纳上述类别的对象<代码>回购的项目可通过
操作员[]访问
过载:

class Logger {
protected:
    //  repository of profilers. each profiler is distinguished by a file name!
    std::map<const std::string, boost::shared_ptr<BasicLogger> > repo; 
public:
    Logger(){} //breakpoints never reach here. why?
    //universal singleton-like access to this class
    static Logger log;
    //returns a member stored in the above 'repo' 
    virtual BasicLogger & operator[](const std::string &key);
};
问题:

问题在于,在程序开始之前,控件直接转到
basiclocker&logger=logger::log[“path_set”]

Q1:为什么控件首先进入此处?仅仅因为
log
是静态的还是匿名名称空间最初也会被处理

不管怎样, 因此,在执行运算符[]时,
repo
似乎未初始化。我添加了一个本地伪变量(
repo\u debug
),其签名与
repo
相同。并使用gdb观察其值:

//local repo_debug
    Details:{... _M_header = {... _M_parent = 0x0, _M_left = 0x7fffffffdc08, _M_right = 0x7fffffffdc08}, _M_node_count = 0}}}
//main 'repo'
    Details:{..._M_parent = 0x0, _M_left = 0x0, _M_right = 0x0}, _M_node_count = 0}}}
Q2.为什么
repo
未初始化?基本上,为什么不调用
记录器的构造函数

Q3.非常感谢您提出解决此问题的建议。
谢谢

Q1:这些声明可能在单独的编译单元中。编译单元之间的静态初始化顺序由实现定义。所以,这是偶然的。我会说这是一个幸运的机会,因为从另一个角度来说,你一开始会认为它只会在另一个cpu/编译器/操作系统上崩溃

问题2:因为匿名命名空间中的
logger
首先被初始化,导致segfault阻止静态
log
进行初始化

第三季度。您可以通过在设计中避免单例来避免问题。但是,如果您想要单例,避免静态初始化顺序失败的一种方法是在第一次使用时构造习惯用法:

Logger& Logger::log() {
   static Logger* log = new Logger();
   return *log;
}
缺点是动态分配的对象从未真正释放(单例将在程序结束时释放,但如果在没有操作系统的情况下运行可能会出现问题)

静态局部变量初始化的线程安全由§6.7/4(c++11草案)中的标准保证:

…否则,这样的变量是 控件第一次通过其声明时初始化;这样的变量被认为是在 完成其初始化。如果初始化通过抛出异常退出,则初始化 未完成,因此将在控件下次输入声明时重试如果控件进入 在初始化变量时并发声明,并发执行应等待 初始化完成。


早期的标准和VisualC++中,可以确保在静态初始化期间调用的至少一个构造函数中调用了<代码>日志(在主程序可以生成任何线程之前发生)。我的初始外观:您的静态和全局正在加速初始化。猜猜谁输了。

Logger::log
实例化在哪里?所有这些
Logger=…
在哪里?同一个编译单元?不同的编译单元?在第二种情况下,您遇到了麻烦,初始化顺序没有定义。如果您希望以这种方式使用日志,请为日志创建一些getter(getter将第一次检查并创建日志,可能使用原子)。或者在一个文件中实例化所有记录器。这种方法是线程安全的吗?我指的是通过局部静态创建单例。那么,这个局部静态在内部使用了一些原子?当多个线程同时请求记录器时,不能多次创建它?正确,至少在c++11中是这样。我不确定早期standards.Thx中的保证。还有一个问题。
static Logger log
(没有
new
)也可以工作吗?那么在这种情况下,破坏是什么呢?@ USER 2079303:它不是VisualC++(还)
//local repo_debug
    Details:{... _M_header = {... _M_parent = 0x0, _M_left = 0x7fffffffdc08, _M_right = 0x7fffffffdc08}, _M_node_count = 0}}}
//main 'repo'
    Details:{..._M_parent = 0x0, _M_left = 0x0, _M_right = 0x0}, _M_node_count = 0}}}
Logger& Logger::log() {
   static Logger* log = new Logger();
   return *log;
}