muduo网络库核心代码阅读(copyable,noncopyable,Logger)(1)

news/2025/2/15 15:42:09/文章来源:https://www.cnblogs.com/xiaodao0036/p/18717044

前言

Muduo 是一个基于 Reactor 模式的高性能 C++ 网络库,由陈硕开发,主要用于 Linux 环境下的多线程服务器编程。它强调易用性和高性能,适合开发高并发的网络应用。

copyable,noncopyable是muduo库的两个重要接口,前者用来显示指出类的值属性,后者用来禁止拷贝构造和拷贝赋值,能够有效提升项目中程序设计的规范性。而Logger是muduo日志库的核心类,通过格式化日志信息,帮助开发者有效调试程序,定位问题。

copyable和noncopyable

copyable源码(中文注释是我的补充)

#ifndef MUDUO_BASE_COPYABLE_H       //防止重复包含
#define MUDUO_BASE_COPYABLE_Hnamespace muduo     //命名空间
{// A tag class emphasises the objects are copyable.(标签类)
// The empty base class optimization applies.(空基类优化)
// Any derived class of copyable should be a value (值类型)
type.
class copyable
{
protected:copyable() = default;       //默认保护构造函数~copyable() = default;      //默认保护析构函数
};}  // namespace muduo#endif  // MUDUO_BASE_COPYABLE_H
  • 标签类:没有成员变量,且构造函数为为protected,只能被子类调用,强调其继承对象是可拷贝的。
  • 空基类优化:基类没有成员变量,编译器会优化其大小为0,减少内存占用。
  • 值类型:派生类应该都为值类型。

noncopyable源码

#ifndef MUDUO_BASE_NONCOPYABLE_H        //防止重复包含
#define MUDUO_BASE_NONCOPYABLE_Hnamespace muduo     //命名空间
{class noncopyable
{
public:
//删除拷贝构造和拷贝赋值,其派生子类只能移动
noncopyable(const noncopyable&) = delete;
void operator=(const noncopyable&) = delete;protected:
//保护构造和析构,无法直接实例化
noncopyable() = default;
~noncopyable() = default;
};}  // namespace muduo#endif  // MUDUO_BASE_NONCOPYABLE_H

禁止拷贝构造和拷贝赋值,其派生子类只能移动。避免子类产生多个实例化或者多个对象引用管理资源,适用于单例类、资源管理类等。

通过 copyable 和 noncopyable,可以显式地表达类的设计意图,使代码更易于理解和维护。

Logger

logger类是muduo网络库的日志类,用于记录程序运行时的日志信息,格式化输出。

LogLevel

//定义了日志级别
enum LogLevel
{TRACE,    //跟踪信息DEBUG,      //调试信息INFO,       //一般信息WARN,      //警告ERROR,      //错误FATAL,       //崩溃NUM_LOG_LEVELS,      //日志级别数量
};

宏定义

muduo日志库通过宏定义来简化日志输出,总共有八个级别的宏定义,其中前三个级别的使用受当前全局日志级别影响,需要用户手动设置。

#define LOG_TRACE if (muduo::Logger::logLevel() <= muduo::Logger::TRACE) \
muduo::Logger(__FILE__, __LINE__, muduo::Logger::TRACE, __func__).stream()
#define LOG_DEBUG if (muduo::Logger::logLevel() <= muduo::Logger::DEBUG) \
muduo::Logger(__FILE__, __LINE__, muduo::Logger::DEBUG, __func__).stream()
#define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \
muduo::Logger(__FILE__, __LINE__).stream()
#define LOG_WARN muduo::Logger(__FILE__, __LINE__, muduo::Logger::WARN).stream()
#define LOG_ERROR muduo::Logger(__FILE__, __LINE__, muduo::Logger::ERROR).stream()
#define LOG_FATAL muduo::Logger(__FILE__, __LINE__, muduo::Logger::FATAL).stream()
#define LOG_SYSERR muduo::Logger(__FILE__, __LINE__, false).stream()
#define LOG_SYSFATAL muduo::Logger(__FILE__, __LINE__, true).stream()

__FILE__是当前源代码的文件名,包括路径;__LINE__是当前源代码的行号;__func__是当前函数名;他们都是C/C++预定义宏。Logger::stream()返回一个LogStream对象的引用,由于重载了<<运算符,因此可以通过<<接受信息,和std::cout一致。

构造函数

Logger(SourceFile file, int line);
Logger(SourceFile file, int line, LogLevel level);
Logger(SourceFile file, int line, LogLevel level, const char* func);
Logger(SourceFile file, int line, bool toAbort);

实现

Logger::Logger(SourceFile file, int line)
: impl_(INFO, 0, file, line)
{
}Logger::Logger(SourceFile file, int line, LogLevel level, const char* func)
: impl_(level, 0, file, line)
{
impl_.stream_ << func << ' ';
}Logger::Logger(SourceFile file, int line, LogLevel level)
: impl_(level, 0, file, line)
{
}Logger::Logger(SourceFile file, int line, bool toAbort)
: impl_(toAbort?FATAL:ERROR, errno, file, line)
{
}

SourceFile 是Logger的内部类,用于从文件路径中提取文件名
impl_ 是日志的具体实现类,用于构建日志内容等

Impl

Impl是Logger的内部类,用于实现日志的具体内容,包括日志级别、时间、文件名、行号、内容等。

class Impl
{
public:typedef Logger::LogLevel LogLevel;Impl(LogLevel level, int old_errno, const SourceFile& file, int line);void formatTime();void finish();Timestamp time_;        LogStream stream_;      LogLevel level_;        //日志级别int line_;              //行号SourceFile basename_;       //文件名
};

Timestamp是muduo实现的时间戳类,用于记录并格式化当前时间
LogStream是muduo实现的日志流类,重载了<<运算符

析构函数

由于宏定义语句中构造的是匿名类,因此会在调用结束后直接进行析构。
muduo通过析构函数完成最后的输出,将日志内容拷贝到标准输出。

#include <iostream>class A {
public:A() {std::cout << "the constructor of A is called" << std::endl;}~A() {std::cout << "the destructor of A is called" << std::endl;}void print() {std::cout << "the print function of A is called" << std::endl;}
};#define Func A().print();int main() {Func;std::cout << "the main function is end" << std::endl;return 0;
}

输出:
the constructor of A is called
the print function of A is called
the destructor of A is called //先执行析构
the main function is end

析构函数实现
Logger::~Logger()
{//最后往这条日志消息里面插入:-文件名:行数\nimpl_.finish();//获取日志数据的引用const LogStream::Buffer& buf(stream().buffer());//输出日志内容g_output(buf.data(), buf.length());//如果日志级别是FATAL,则刷新缓冲区并调用abort()函数if (impl_.level_ == FATAL){g_flush();abort();}
}

g_output 和 g_flush

Logger::OutputFunc g_output = defaultOutput;
Logger::FlushFunc g_flush = defaultFlush;

OutPutFunc和FlushFunc是Logger类中定义的两个函数指针:

typedef void (*OutputFunc)(const char* msg, int len);
typedef void (*FlushFunc)();

不同调用对象可以让日志输出到不同的地方

默认输出
void defaultOutput(const char* msg, int len)
{
size_t n = fwrite(msg, 1, len, stdout);     //写到标准输出
//FIXME check n
(void)n;    //忽略未使用对象,避免编译警告
}
默认刷新
void defaultFlush()
{
fflush(stdout);     //刷新标准输出缓冲区
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/884280.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ABP】项目示例(2)——聚合根和实体

聚合根和实体 在上一章节中,已经完成了项目搭建的前置准备,在这一章节中,实现领域层的聚合根和实体 创建名称为General.Backend.Domain的标准类库,分别新建名称为Entities、Services、IRepositories和Specifications的文件夹,用于存放实体和聚合根、领域服务、仓储接口和规…

P1896 [SCOI2005] 互不侵犯(状态压缩)

位运算符好麻烦,没打括号被卡了半天 #include<iostream> #define int long long using namespace std; int f[12][100][1<<11]; int s[1<<11]; int num[1<<11]; signed main(){int n,k;cin>>n>>k;int cnt=0;for(int i=0;i<(1<<…

200N03-ASEMI豆浆机专用MOS管200N03

200N03-ASEMI豆浆机专用MOS管200N03编辑:ll 200N03-ASEMI豆浆机专用MOS管200N03 型号:200N03 品牌:ASEMI 封装:TO-252 批号:最新 最大漏源电流:200A 漏源击穿电压:30V RDS(ON)Max:1.8mΩ 引脚数量:3 芯片个数: 沟道类型:N沟道MOS管、中低压MOS管 漏电流:ua 特性:…

第七章-收益归因:Brinson模型

例子 现有一个投资组合,其基准组合为:70%中证800,20%债券,10%现金,如下:基金经理主动投资,对资产权重进行调整。假设基准组合收益率为\(r\)。若是看好股票,那就多配置一些股票,调整中证800权重为\(w_1^{\prime}\)。则收益调整为(\(w_1^{\prime}-w)(r_1-r)\)。会有两种情…

我用GPT干什么

有几天没有更新文章了,一方面因为感觉GPT出来了,写什么都不香了,非得写点关于GPT的才有资格出来和大家见面;另一方面,确实最近一段时间也在全面拥抱GPT:学习,总结,思考。所以今天就想随心所欲地说说GPT使用感受。其实GPT出来没多长时间,就注册账号,并体验了网页版,更…

金融期权

金融期权品种一览上海证券交易所品种 行权方式 上市日期华夏上证50ETF期权 欧式 2015-02-09华泰沪深300ETF期权 欧式 2019-12-23南方中证500ETF期权 欧式 2022-09-19华夏上证科创板50ETF期权 欧式 2023-06-05易方达上证科创板50ETF期权 欧式 2023-06-05深圳证券交易所品种 行权…

从ClickHouse中流式查询大数据

提示:本篇不适合手机阅读,主要为了提供代码实现。为了减速少大的Excel文件在内存中驻留,使用流的方式,边查询边组装,边下载文件相对来说是一个好的方式,下面是基于ClickHouse数据源的方式,下载100万条记录的处理方式,本地测试,内存只有100多M的使用,下载完后就会释放…

Axure9下载完美汉化及破解

一)Axure9下载 复制链接到浏览器,复制后需删除作者后面的部份才能打开!Windows系统: https://pan.baidu.com/s/1CF-lpmzzaevUX2lCZUmmiAMac新系统(M芯片) https://pan.baidu.com/s/1k73IJBAdlwUL1YPPRWXchA 提取码: 1323 注:M1版本自带破解,仅需汉化即可Mac旧系统(int…

单视图度量(Single View Metrology)总结

前面我们介绍了标定相机,并且我们知道,如果我们能够确定三维点的坐标以及标定相机的参数,就能够确定它在图像平面的位置。那我们现在思考一个问题,如果我们知道图像平面的坐标以及标定相机的参数,我们能够确定这个三维点的位置吗? 答案是否定的。因为一般情况下,三维点可…

简说VS中的.http

在VS17.5中,加入了一个.http文件,应该和你想的一样,就是一个存放请求的文件,关键是他能执行请求,很像curl。不过市面上相似的工具有很多,比如Postman就做的很好了,那为什么VS还要引入呢?我的简单理解,虽然Postman好用,但毕竟和VS中的源码是分离的,即使Postman等工具…

P1119 灾后重建

链接 https://www.luogu.com.cn/problem/P1119 题目知识点floyd算法思路看题解,讲的差不多,本篇就是记录下写过的题。 唯一要注意的就是当遍历k(本代码用cnt代替)时,ij都要从0取到n-1。代码 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm&g…

库卡机器人维修伺服电机刹车故障维修

库卡机器人作为工业自动化领域的佼佼者,其伺服电机系统的稳定性和可靠性对于生产线的顺畅运行至关重要。然而,在实际应用中,KUKA工业机械手伺服电机刹车故障时有发生,这不仅会影响机器人的正常运行,还可能对生产安全造成威胁。 ,kuka机器人电机刹车故障通常表现为以下几种…