每天学一点点,只有周末有大把的时间。本篇博客重点讲解我不熟练的,而一些muduo库设计的巧妙的东西,如果想学习深入理念这篇博客完全不太适合。等学完muduo之后,最后仿一个muduo出来,再重新架构一下自己的网络库,一个自己写的小网络库我给他取名为Pine
目录
1、宏函数的使用
首先是日志的宏函数,平常很少接触宏函数,只是知道有这么个东西,但是并没有写过宏函数。\表示的是后面还有语句的,do while是确保程序一定会执行一次,避免漏掉什么函数宏函数的优缺点
#define LOG_FATAL(logmsgFormat,...) \
do \
{ \
Logger& logger = Logger::instance(); \
logger.setLogLevel(FATAL); \
char buf[1024] = { 0 }; \
snprintf(buf,sizeof(buf),logmsgFormat,##__VA_ARGS__); \
logger.log(buf); \
}while(0)
2、如何添加事件、或者删除事件?
平常写过epoll的朋友一定用过 EPOLLIN | EPOLLET这样的写法,添加一个事件用|或操作就好了。
删除事件我一直没想明白要怎么搞,百思不得其解也陷入了误区。
假设有两个值一个初始值一个事件值int init_ = 6;int event = 5;我寻思添加操作也不难嘛,直接init_ |= event,确实是这么简单,删怎么删呢?删是 init_ &= ~event;当时我天真的以为删除的话要把init_的值恢复成原来的模样,我咋想 init_ &= ~event之后,值也不可能是6啊,(最后的值是6)我真的陷入了好久。直到我看到事件是否存在的函数之后,我恍然大悟了bool cmp(){ return init_ & event ;}
陷入的误区就是,人家并没有要求init_回到初值啊,只不过是比较是不是在同位上都有1,只要有一个1就说明事件是添加的(true),false是事件已经被删除了。恍然大悟、醍醐灌顶、彻底想明白了,算法真是太妙了!
| 或操作保证了有一个1的位就一定是1了,删掉的话先去反,保证去掉的值和以前|或出来的值位相反,再进行与操作,保证了正确性!
3、命名的讲究
我们可以清楚的看到每个成员变量后面都加了_,系统的变量的_是加在前面的,所以muduo成员变量在后面加_,而函数的局部的变量不加_,这样都很好的区分
4、nocopyable和copyable
我认为好的代码就是通俗易懂、效率高,而不是很多人使用C++11的包扩展加上decltype(auto)返回值的各种秀技的代码。我认为如果那种代码不可替代那么写无可厚非,有可替代除了不想让人好好读以外我真的看不出来有什么用。
一目了然 Channel不可以被copyable,类nocopyable怎么实现的呢,在C++11里面很容易就实现了,如下所示。直接把拷贝构造和拷贝运算符给delete掉。
class Channel : public nocopyable
#ifndef NOCOPYABLE_H_INCLUDED
#define NOCOPYABLE_H_INCLUDED
/*
*nocopyable被继承后,可以构造和析构
*但无法拷贝和赋值操作
*/
class nocopyable
{
private:
nocopyable(const nocopyable&) = delete;
void operator=(const nocopyable&) = delete;
protected:
nocopyable() = default;
~nocopyable() = default;
};
#endif
同样的还有copyable,人们一眼就知道这个类可以copyable了。这就是nocopyable和copyable所能带来的好处啦!
#ifndef COPYABLE_H_INCLUDED
#define COPYABLE_H_INCLUDED
//可以被拷贝的类
class copyable {
public:
copyable() = default;
~copyable() = default;
};
#endif // !COPYABLE_H_INCLUDED
5、vscode控制缩进
以前在windows使用VS写C++,ctrl+alt就可以控制缩进了,在vscode用ctrl+[(向左)或者ctrl+](向右)控制缩进
6、make_unique的新理解,怎么托管new指针,什么时候使用make_unique
以前对make_unique的理解不深,在学习muduo网络库的时候再次加深了智能指针的操作。std::vector<std::unique_ptr<EventLoopThread>> threads_;
如果想托管一个new出来的,就像如下图片显示代码一样,直接定义一个出来。千万不要想着new出来一个指针,再用make_unique来定一个智能指针。可以看下面的代码。如果没有new指针的话,最好使用make_unqiue来进行初始化。
// new出来的对象最好采用上面的方法,直接托管new出来的指针,而不是采用make_unique
int* t = new int(2);
vec.emplace_back(unique_ptr<int>(*t));// new了一个新的unique_ptr对象
delete t; // 别忘了delete t,否则内存泄露
7、#pragma once
这个和
#ifndef
#define
#endif
用处是一样的都是为了头文件被重复包含,if end是C++语言提供的,#pragma once是编译器所提供的