在静态初始化期间是否保证可用计数

Is cout guaranteed available during static deinitialization?

本文关键字:是否 静态 初始化      更新时间:2023-10-16

我有一个准单例类(在大多数情况下,准单例指的是单个对象,它是一个函数静态,但用户也可以为短期使用构造自己的本地副本),我想从它的析构函数中写入cout,并且想知道cout是否保证在程序终止后的静态取消初始化阶段可用。从这个问题看来,答案是肯定的(函数静态初始化对象的析构函数应该从它们被构造时起以相反的顺序调用,应该在cout设置之后),但我想检查一下。

// Count calls to a logging function from some point in our code, to determine
// how many times it gets executed during a run, then report calls at the end
// of the program.  A quick-and-dirty way of determining how often we execute
// code.
class callCounter;
class callCounter {
public:
    callCounter() : has_calls_(false), counts_() {}
    ~callCounter () {report(std::cout);}
    void logCall(const std::string callSite);
    void report(std::ostream &os);
    void reset();
    static callCounter *theCounter();
private:
    typedef std::map<std::string, callCount> COUNTMAP;
    bool has_calls_;
    COUNTMAP counts_;
};
callCounter *callCounter::theCounter()
{
    static callCounter theCounts;
    return &theCounts;
}

典型的用法是:

callCounter::theCounter()->logCall("foo");

那么,在析构函数中使用cout是否保证安全(至少就使用cout本身而言——可以说是完全安全的,我应该将报告包装在try块中,以防write抛出异常)?

简短回答:是

长答案:Yes

标准库使用了一些技巧来确保std::cout(和std::cin/std:cerr)在任何其他对象之前可用(但是您必须#include 在翻译单元)。因为它们首先被创建(销毁规则的相反顺序保证),它们在对象之后被销毁。

参见:n3242 (practical the c++ 0x standard Pub: 2011-02-28)

标准iostream对象第二款

对象是在类ios_base::Init对象第一次被构造之前或期间被构造的,在任何情况下都是在main函数体开始执行之前。这些对象在程序执行期间不会被销毁。在翻译单元中包含的结果应该像定义了一个ios_base::Init实例,静态存储时间。同样,整个程序应该表现得好像至少有一个具有静态存储时间的ios_base::Init实例。

添加高亮显示。

来自n1804(基本上是2003年的标准:Pub: 2005-04-27)

标准iostream对象第二款

在相应的宽字符流和窄字符流上的混合操作遵循与在文件上的混合操作相同的语义,如ISO C标准修正案1中规定的那样。对象被构造,关联在类ios_base::Init对象第一次构造之前或期间建立,在任何情况下都是在main主体开始执行之前。280.

不幸的是,使其成为保证的位是在脚注中(这是非规范的(即它不能保证实现者应该尝试和实现的)。

带脚注:

280)静态对象的构造函数和析构函数可以访问这些对象,从stdin读取输入或将输出写入stdout或stderr。