【问题标题】:Is cout guaranteed available during static deinitialization?cout 在静态取消初始化期间是否保证可用?
【发布时间】:2011-08-02 22:42:07
【问题描述】:

我有一个我想要的准单例类(准单例在大多数情况下是指作为静态函数的单个对象,但用户也可以构建自己的本地副本以供短期使用)从其析构函数写入 cout,并想知道 cout 在程序终止后的静态反初始化阶段是否保证可用。从this question 看来答案是肯定的(函数静态初始化对象的析构函数应该从构造时的相反顺序调用,这应该在 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 块中,以防写入引发异常。) ?

【问题讨论】:

    标签: c++


    【解决方案1】:

    简短回答:是的

    长答案:是的

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

    参见:n3242(实际上是 C++0x 标准发布:2011-02-28)

    27.4 标准 iostream 对象

    第 2 段

    在第一次构造 ios_base::Init 类的对象之前或期间的某个时间构造对象并建立关联,并且无论如何在 main 的主体开始执行之前。在程序执行期间对象不会被破坏。 包含在翻译单元中的结果应该就像 定义了一个具有静态存储持续时间的 ios_base::Init 实例。类似地,整个程序的行为就好像至少有一个具有静态存储持续时间的 ios_base::Init 实例。

    添加了突出显示。

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

    27.3 标准 iostream 对象

    第 2 段

    在相应的宽字符流和窄字符流上混合操作遵循与在 FILE 上混合此类操作相同的语义,如 ISO C 标准的修订 1 中所述。构造对象,并在第一次构造类 ios_base::Init 的对象之前或期间建立关联,并且无论如何在 main 的主体开始执行之前。程序执行期间对象不会被销毁280.

    不幸的是,脚注中有一点可以保证它(这是非规范性的(即它不能保证实现者应该尝试和实现的目标)。

    附注:

    280) 静态对象的构造函数和析构函数可以访问这些对象以从标准输入读取输入或将输出写入标准输出或标准错误。

    【讨论】:

    • 出于好奇,这实际上是否直接包含在标准中?
    • 谢谢。有了那里标准的引用,我想说这是明确的答案。
    • @dewtell:此答案仅适用于 C++0x。也许我错过了,但我在问题中看不到这样的保证。在 C++03 中,它不能保证自动初始化,尽管你可以自己做。我在我的博客上写过它,但我只是注意到它说我的帐户已被暂停......
    • @dewtell:没关系,你说的是破坏。您在 C++03 和 C++0x 中都很好,尽管就像我在之前的评论中所说的那样,出于不同的原因。
    • 这可以追溯到摩西时代(尽管标准中的确切措辞随着时间的推移略有变化)。在静态存储持续时间对象的构造函数/析构函数中使用 std::cout/std::cin 是安全的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 2013-04-24
    • 1970-01-01
    相关资源
    最近更新 更多