由于复制

时间:2015-05-21 11:30:28

标签: c++ logging copy move

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

但我希望有一条消息记录范围的时间。因此它会影响自创建以来的时间以及删除后的时间。因此我需要将它分配给范围中的变量,例如此marko:#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
}

1 个答案:

答案 0 :(得分:2)

您正在遇到运营商优先级问题。当您使用宏时:

LOG_SCOPE_TIME << "Some scope";

扩展为:

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

评估为:

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

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

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

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

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

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

那里没有问题。