找出std :: ostream&是否引用了全局对象

时间:2019-04-05 07:33:44

标签: c++ output outputstream

如果采用以下方法

template<typename... Args>
void report(std::ostream&str, Args&&... args)
{
    (str << ... << args);
}

是从具有相同str的不同线程中同步调用的,来自不同线程的写操作可能会被破坏。因此,我改用

template<typename... Args>
void report(std::ostream&str, Args&&... args)
{
    std::ostringstream ostr;
    (ostr << ... << args);
    str << ostr.str();
}

现在,我想知道是否可以检测出是否确实有必要,即

{
    if(is_global_object(str)) {      // how to implement this?
        std::ostringstream ostr;
        (ostr << ... << args);
        str << ostr.str();
    } else
        (str << ... << args);
}

问题:如何实现is_global_object(str)?我很乐意检测所有std::coutstd::wcoutstd::clogstd::wclogstd::cerrstd::wcerr

2 个答案:

答案 0 :(得分:3)

不,绝对不可能。如果一个线程创建一个本地ostream然后将对它的引用传递给另一个线程怎么办?不是全球性的,但仍然共享。对象的全局性并不能确定其位置。

答案 1 :(得分:1)

因此,首先无法检查某些引用是否是对全局对象的引用。至少并非没有一些特定于平台的硬黑客(静态内存扫描?),这些黑客可能无法正常工作。不要走那条路。

第二个(更重要的是)您的问题不是“全局”的。它是“共享的”。您为什么认为变量必须是全局变量才能共享?另一方面,可能存在不共享的全局变量。但是无论如何,也没有解决方案。没有hack可以帮助您。

第三,您的中间代码也不是线程安全的。不能保证单次写入必须是线程安全的。在某些情况下,它是(std :: cout),但没有对std :: ostream的保证。我可以使用非线程安全的写操作轻松地编写自己的流。

最后但并非最不重要的一点是,您可以利用类和互斥锁来避免所有这些情况。像这样:

class Logger {
    public:
        Logger(std::ostream& stream): stream {stream}
        {};

        template<typename... Args>
        void log(Args&&... args)
        {
            std::lock_guard<std::mutex> lg {mu};
            (stream << ... << args);
        }

    private:
        std::ostream& stream;
        std::mutex mu;
};

完全不用担心所有线程安全问题。

为了更好地扩展,您可能需要看一下消息的无锁排队。