标题基本上都说明了,我想知道c ++类的静态成员何时被初始化以及何时超出范围。
我需要这个来解决以下问题。我有很多Foo类的对象,每个对象都需要访问一个资源,由另一个类Bar封装。同步不是问题,所以我希望所有对象共享相同的Bar实例。
我正在使用一个简单的托管指针进行引用计数。
我可以执行以下操作:
class Foo {
private:
static managed_pointer<Bar> staticBar;
public:
Foo() {
if(!staticBar)
staticBar = new Bar;
}
/*
* use staticBar in various non-static member functions
*/
};
managed_pointer<Bar> Foo::staticBar = NULL;
managed_pointer staticBar应该在它超出范围时立即删除它 - 但是什么时候会发生?当Foo的最后一个实例被破坏时?在申请退出?
感谢您的建议!
答案 0 :(得分:13)
static
和全局变量在程序开始之前初始化(在调用main
之前,程序实际上在此之前开始)并在main
退出后超出范围。
异常 - 本地静态(在函数内声明的静态变量)和未使用的模板类static
成员。
它与实例数无关。
答案 1 :(得分:2)
标准没有指定初始化的精确顺序,它是特定于实现的。它们将在程序开始时实例化,并在最后解除分配。
你必须非常小心你正在做的事情,因为如果你有一些其他依赖这个对象存在的静态对象,它就是UB。没有人知道他们将以什么顺序进行初始化。
你可能会调查类似boost :: call_once的东西以确保它被初始化一次,但我不会依赖于初始化静态的顺序。
就我所知,你的代码可以工作,但我之前被静态初始化问题所困扰,所以我想警告你。
编辑:同样在你的代码中,当managed_ptr超出范围(程序结束)时,它将删除自动分配的内存。但是你不应该在Bar的析构函数中做任何不重要的事情,因为你可以通过调用其他free'd实例甚至是已经被删除的代码来触发UB(因为它发生在我曾经删除动态库的地方)。基本上你是在雷区,所以要小心。
答案 2 :(得分:1)
您提出的第一件问题是范围和生命周期是等效概念的常见误解。他们不是。在某些情况下,与局部变量一样,生命周期绑定到特定的上下文,但情况并非总是如此。
类静态成员变量具有类范围(可在程序中随处任何)和静态生存期,这意味着它将按照相对于同一翻译单元中的其他静态变量的顺序进行初始化,并且相对于其他翻译单元中的其他静态变量以未定义的顺序进行初始化,在 main之前(警告:不需要执行初始化)在main中的第一个语句之前,但保证在变量的第一个 odr-use 之前。