前言
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); //刷新标准输出缓冲区
}