【问题标题】:Logger logs 2 times instead of one time because of copyLogger 记录 2 次而不是 1 次,因为复制
【发布时间】:2015-05-21 11:30:27
【问题描述】:

我正在编写自己的 Logger。我知道那里有很多,但我想自己写。它有在离开作用域时被记录的消息。因此,如果我调用 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
}

【问题讨论】:

  • 你能想出一个更简单的例子吗?这是很多代码。
  • 我尽力给我几分钟
  • shell 我将它添加到问题中还是像这样?这种用法___t或多或少安全吗?
  • 是的,您应该始终寻找一个最小、完整且可验证的示例 - 因此您应该将您的问题编辑得更短。另外,您应该将___t 重命名为t___

标签: c++ logging copy move


【解决方案1】:

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

LOG_SCOPE_TIME << "Some scope";

扩展为:

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

评估结果为:

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

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

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

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

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

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

那里没有问题。

【讨论】:

  • 是的,那个小东西按预期修复了它。非常感谢您抽出宝贵时间检查此内容。
猜你喜欢
  • 1970-01-01
  • 2011-03-28
  • 2013-12-30
  • 1970-01-01
  • 2019-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多