由于复制,记录器记录 2 次而不是一次

Logger logs 2 times instead of one time because of copy

我正在编写自己的记录器。我知道那里有很多,但我想自己写。它具有在离开范围时记录的消息。因此,如果我调用 Logger::Error(__FILE__,__LINE__) << "some error" 它会直接记录下来,因为没有分配给变量。

但我想要一条记录示波器时间的消息。所以它测量了自创建和删除以来的时间。因此我需要将它分配给范围内的变量,例如这个标记:#define LOG_SCOPE_TIME LogTimer ___t = Logger::Timer(__FILE__,__LINE__) 可以这样使用:

int main()
{
    {
    LOG_SCOPE_TIME << "Some scope";
    //do something to mesure
    }
}

示例输出:

[timer][File:main.cpp][Line:19][thread:8024][21-05-2015][13:15:11] Some scope[0µs]
[timer][File:main.cpp][Line:19][thread:8788][21-05-2015][13:15:11] Some scope[118879µs]

但这实际上导致了2条日志。第一个临时创建的 LogTime 对象(时间为 0µs),第二个为实际范围时间。

我该如何防止这种情况发生?有什么建议么?这是一个简化的例子:

#include <iostream>
#include <chrono>

class LogTimer {
    std::string str;
    std::chrono::high_resolution_clock::time_point m_start;
public:
    LogTimer(const std::string& file, int i)
        : m_start(std::chrono::high_resolution_clock::now())
    {
        str = file + ':' + std::to_string(i);
    }

    ~LogTimer() {
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>
                    (end - m_start).count();
        std::cout << str << " [" << duration << "µs]\n";
    }

    LogTimer& operator<<(const std::string& p) {
        str += '[' + p + ']';
        return *this;
    }
};

namespace Logger {
    LogTimer Timer(const std::string& f, int i) {
        return LogTimer(f, i);
    }
}

#define LOG_SCOPE_TIME LogTimer ___t = Logger::Timer(__FILE__,__LINE__)

int main() 
{
    LOG_SCOPE_TIME << "something"; // logs two lines
}

您 运行 遇到了某种运算符优先级问题。当您使用宏时:

LOG_SCOPE_TIME << "Some scope";

扩展为:

LogTimer ___t = Logger::Timer(__FILE__,__LINE__) << "Some scope";

评估为:

LogTimer ___t = (Logger::Timer(__FILE__,__LINE__) << "Some scope");

因为 << 的优先级高于 =。因此,您可以防止发生复制省略,因为编译器现在必须创建一个临时 Timer 来执行 << "Some Scope" 然后 copy___t(从技术上讲,这是一个保留名称)。附加副本意味着附加析构函数,在您的情况下意味着记录了额外的行。

您需要确保复制省略。我能想到的最简单的方法是将宏更改为:

#define LOG_SCOPE_TIME LogTimer ___t = Logger::Timer(__FILE__,__LINE__); ___t

这样,您的原始示例将扩展为:

LogTimer ___t = Logger::Timer(__FILE__,__LINE__); ___t << "Some scope";

没有问题。