当我在C++中使用静态变量时,我常常想要初始化一个变量,将另一个变量传递给它的构造函数.换句话说,我想创建彼此依赖的静态实例.
在单个.cpp或.h文件中,这不是问题:将按照声明的顺序创建实例.但是,如果要使用另一个编译单元中的实例初始化静态实例,则无法指定顺序.结果是,根据天气,可能会发生构建依赖于另一个实例的实例,并且之后才构建另一个实例.结果是第一个实例初始化不正确.
有谁知道如何确保以正确的顺序创建静态对象?我已经搜索了很长时间寻找解决方案,尝试了所有这些解决方案(包括Schwarz Counter解决方案),但我开始怀疑有一个确实有效.
一种可能性是使用静态函数成员的技巧:
Type& globalObject()
{
    static Type theOneAndOnlyInstance;
    return theOneAndOnlyInstance;
}
实际上,这确实有效.遗憾的是,您必须编写globalObject().MemberFunction()而不是globalObject.MemberFunction(),从而导致一些令人困惑和不雅的客户端代码.
更新:感谢您的反应.遗憾的是,我确实似乎回答了自己的问题.我想我必须学会忍受它......
c++ static-variables initialization-order static-order-fiasco
我们遇到了静态初始化命令惨败的一些问题,我正在寻找方法来梳理大量代码以找到可能发生的事件.有关如何有效地做到这一点的任何建议?
编辑:我得到了一些关于如何解决静态初始化顺序问题的好答案,但这不是我的问题.我想知道如何查找受此问题影响的对象.在这方面,Evan的答案似乎是迄今为止最好的答案; 我不认为我们可以使用valgrind,但我们可能有可以执行类似功能的内存分析工具.只有在给定构建的初始化顺序错误的情况下才能捕获问题,并且顺序可以随每个构建而改变.也许有一个静态分析工具可以捕捉到这一点.我们的平台是在AIX上运行的IBM XLC/C++编译器.
我正在读一本关于SIOF的书,它举了一个例子:
//file1.cpp
extern int y;
int x=y+1;
//file2.cpp
extern int x;
int y=x+1;  
现在我的问题是:
在上面的代码中,会发生以下事情吗?  
我今天早上和一位同事就静态变量初始化顺序进行了讨论.他提到了Nifty/Schwarz计数器,我(有点)感到困惑.我理解它是如何工作的,但我不确定这在技术上是否符合标准.
假设以下3个文件(前两个是来自更多C++习语的 copy-pasta ):
//Stream.hpp
class StreamInitializer;
class Stream {
   friend class StreamInitializer;
 public:
   Stream () {
   // Constructor must be called before use.
   }
};
static class StreamInitializer {
  public:
    StreamInitializer ();
    ~StreamInitializer ();
} initializer; //Note object here in the header.
//Stream.cpp
static int nifty_counter = 0; 
// The counter is initialized at load-time i.e.,
// before any of the static objects are initialized.
StreamInitializer::StreamInitializer ()
{
  if (0 == nifty_counter++)
  {
    // Initialize Stream …我有下一个情况:我需要在独立静态库中创建小部件,然后将其与最终应用程序链接(visual c ++ 9.0,qt 4.5).此静态窗口小部件库包含一些资源(图标),并包含多个.cpp文件(每个文件包含独立窗口小部件).据我所知,我必须初始化qt资源系统,如果我在静态库中使用它们(资源),调用"Q_INIT_RESOURCE(resource_file_name)".我用下一个代码(在静态库中的每个.cpp文件中)解决了这个问题:
#include <QAbstractButton>
namespace {
struct StaticLibInitializer
{
    StaticLibInitializer()
    {
        Q_INIT_RESOURCE(qtwidgets_custom_resources);
    }
};
StaticLibInitializer staticLibInitializer;
} 
// ... widget code ....
我没有使用第一种方法,而是使用初始化代码在静态库项目中创建了单独的init.cpp文件(以避免在每个.cpp文件中包含初始化代码),但这不起作用.
为什么这不起作用?
这种使用StaticLibInitializer的方法在各种编译器和平台之间是否安全且可移植?
在他的"用C++思考"(第10章)中,Eckel描述了Jerry Schwarz为解决惨败而开创的技术.他说如果我们想要将x初始化为100和y到200并在所有翻译单元之间共享它们,我们创建一个如下所示的Initializer.h:
extern int x;
extern int y;
class Initializer {
   static int initCount;
   // if (initCount++ == 0) x = 100 & y = 200
   /* ... */
};
static Initializer init;
在实现文件中我们有
#include "Initializer.h"
int x;
int y;
int Initializer::initCount;
和Eckel说"静态初始化(在实现文件中)将强制所有这些值为零".
让我考虑以下情况:编译器在包含该头的其他文件之后处理实现文件(这意味着x和y已经在该另一个文件中设置为100和200).编译器看到了int x,它会做什么?它会将x和y设置为零,从而消除初始化和以前文件中的所有可能更改吗?但如果确实如此,那么initCount也将设置为零,打破整个技术.
这里最近的一个问题有以下代码(好吧,类似于这个)来实现没有同步的单例.
public class Singleton {
    private Singleton() {}
    private static class SingletonHolder { 
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
现在,我想了解这是做什么的.由于实例是static final,它建立在任何线程调用之前很久,getInstance()所以不需要同步.
只有当两个线程试图同时调用时才需要同步getInstance()(并且该方法在第一次调用"static final"时而不是在第一次调用时进行构建).
因此我的问题基本上就是:为什么你会喜欢懒惰的单身人士建构:
public class Singleton {
    private Singleton() {}
    private static Singleton instance = null;
    public static synchronized Singleton getInstance() {
        if (instance == null)
            instance = new Singleton();
        return instance;
    }
}
我唯一的想法是使用该static final方法可能会引入排序问题,如C++静态初始化顺序惨败.
首先,Java实际上 …
有一次,我在读一个真棒C++ FAQ(这是真的好!)并阅读主题如何防止静态初始化命令"惨败".因此作者建议将静态变量包装到函数中,从而通过维护变量的创建顺序来防止"惨败".但在我看来,这是一个粗鲁的解决方法.所以我的问题是,是否有任何现代的,更多的模式导向的方法来防止这种"惨败",但将"静态东西"包装成函数???
c++ static word-wrap static-initialization static-order-fiasco
可能这个全局函数遭受静态初始化惨败吗?
template <typename TFn>
void ParallelFor(int iIni,int iFin,TFn Fn)    
{
  static const unsigned int NThread= std::thread::hardware_concurrency();
  // ...    
}
这里有一些关于"静态初始化顺序惨败"的好问题和答案,但我似乎已经打击了它的另一个表达,特别难看,因为它不会崩溃但是会丢失并泄漏数据.
我有一个自定义C++库和一个链接它的应用程序.库中有一个静态STL容器,用于注册类的所有实例.这些实例碰巧是应用程序中的静态变量.
由于"惨败"(我相信),我们在应用程序初始化期间让容器填满应用程序实例,然后库进行初始化并重置容器(可能是泄漏内存),最后只有来自实例的实例图书馆.
这就是我用简化代码复制它的方法:
mylib.hpp:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class MyLibClass {
    static vector<string> registry;
    string myname;
  public:
    MyLibClass(string name);
};
mylib.cpp:
#include "mylib.hpp"
vector<string> MyLibClass::registry;
MyLibClass::MyLibClass(string name)
: myname(name)
{
    registry.push_back(name);
    for(unsigned i=0; i<registry.size(); i++)
        cout << " ["<< i <<"]=" << registry[i];
    cout << endl;
}
MyLibClass l1("mylib1");
MyLibClass l2("mylib2");
MyLibClass l3("mylib3");
MyApp.cpp中:
#include "mylib.hpp"
MyLibClass a1("app1");
MyLibClass a2("app2");
MyLibClass a3("app3");
int main() {
    cout << "main():" << endl;
    MyLibClass m("main");
} …c++ static initialization static-libraries static-order-fiasco