该专栏记录了在学习一个开发项目的过程中遇到的疑惑和问题。
其教学视频见:[C++高级教程]从零开始开发服务器框架(sylar)
上一篇:C++服务器框架开发1——项目介绍/分布式/#ifndef与#pragma once
C++服务器框架开发2——头文件memory/typedef
- 目前进度
- memory
- typedef
目前进度
目前第一个视频中的log.h编写还没学完,进度如下图。
要点:
- 这几个类定义都写在namespace里,这是为了避免不同头文件的命名冲突。
- 其中的LogAppender的析构函数被定义成虚函数了,因为日志输出地方可能有很多种,到时候就需要用到子类来继承这个父类,所以它的析构函数要设置成虚的。这是考虑到内存泄露问题。简单的讲就是:假设没有写virtual,然后定义了一个基类指针来指向动态的子类,当delete指针时,只会执行基类的析构函数不执行子类的,这就会导致子类中的堆内存没有被释放。而写了virtual的话,则会先执行子类的析构函数,再执行父类的析构函数。可以参考这两篇文章:文章1和文章2。
- LogEvent类中,定义变量时进行了初始化,这是符合C++11规范的。
memory
memory是个标准库,我查了下,它有很多种指针和分配器。从上图的学习进度可以看到,shared_ptr
就是其中一种共享指针。对于它的功能描述,如下:
- “shared_ptr 共享指针,初始化后同指针一样指向一个对象,成员函数use_count() 表示有多少共享指针指向对象,每当shared_ptr被赋值、拷贝的时候,use_count()加1,一个共享指针不再指向对象时,use_count减1。以这种方式构造的,指向同一个对象的指针,use_count是共享的。”
- “shared_ptr 主要的功能是,管理动态创建的对象的销毁。它的基本原理就是记录对象被引用的次数,当引用次数为 0 的时候,也就是最后一个指向某对象的共享指针析构的时候,共享指针的析构函数就把指向的内存区域释放掉。” 代码示例:
#ifndef __HELLOWORLD__
#define __HELLOWORLD__
#include <iostream>
#include <memory>
#include <assert.h>
#endif
int main() {
std::shared_ptr<int> sp(new int(10)); //一个指向整数的shared_ptr
assert(sp.unique()); //现在shared_ptr是指针的唯一持有者
std::shared_ptr<int> sp2 = sp; //第二个shared_ptr,拷贝构造函数
assert(sp == sp2 && sp.use_count() == 2); //两个shared_ptr相等,指向同一个对象,引用计数为2
*sp2 = 100; //使用解引用操作符修改被指对象
assert(*sp == 100); //另一个shared_ptr也同时被修改
sp.reset(); //停止shared_ptr的使用
assert(!sp); //sp不再持有任何指针(空指针)
return 0;
}
typedef
参考自文章3,文章讲得很细,这里我把一些重点的搬运过来。
“任何声明变量的语句前面加上typedef之后,原来是变量的都变成一种类型。”
我的理解就是,用typedef来给某种类型的变量或函数起个名字,然后后面当你需要声明这种类型的变量或函数时,你就可以用这个名字,而无需再写各种复杂的规范描述。下面是文章给的例子,看例子及其注释加深下理解。
//变量
typedef int NUM;
NUM a = 10; // 也可写成`NUM(a) = 10;`
NUM(b) = 12; // 也可写成`NUM b = 12;`
//函数
typedef int f(); // 定义一个名为f, 参数为空, 返回值为int的函数类型
typedef int g(int); // 定义一个名为g, 含一个int参数, 返回值为int行的函数类型
//应用
#include <iostream>
#include <stdio.h>
#include <string>
typedef int P(); // 简单的
typedef void Q(int *p, const std::string& s1, const std::string& s2, size_t size, bool is_true); // 复杂的
class X {
public:
P(eat_shit); // 等价于声明`int eat_shit();`
Q(bullshit); // 等价于声明`void bullshit(int *p, const string& s1, const string& s2, size_t size, bool is_true);`
};
int main() {
X *xx;
printf("shit ret: %d\n", xx->eat_shit());
int a[] = {1, 3, 4, 5, 7};
xx->bullshit(a, "foo", "bar", sizeof(a)/sizeof(int), true);
}
int X::eat_shit() {
return 888;
}
void X::bullshit(int *p, const std::string& s1, const std::string& s2, size_t size, bool is_true) {
std::cout << "s1: " << s1 << ", s2: " << s2 << ", size: " << size << std::endl;
printf("elems:\n");
for(int i = 0; i < size; i++) {
printf("%d %s", *p++, (i == size-1) ? "" : ",");
}
printf("\n");
}
回到这个开发项目来。进度图中的第12行,定义了一个名字为ptr的共享指针,这个共享指针是LogEvent类的。
我还没看后面的代码,但据我的理解,定义这个ptr,可能是因为后面可能需要用很多这种指针,并且不同的类需要定义不同的类的指针,如果能用ptr指代,写代码就方便多了。