From 4922bbf1ebf00909012d52f585d69e344ae77dcf Mon Sep 17 00:00:00 2001 From: Estom Date: Fri, 3 Sep 2021 06:42:58 +0800 Subject: [PATCH] =?UTF-8?q?C++=E5=85=B8=E5=9E=8B=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- C++/mianshi.cpp | 8 - C++/典型实现/1 内存分配器.md | 107 ++++++++++ C++/典型实现/2 智能指针.md | 119 +++++++++++ C++/典型实现/3 字符串类.md | 142 +++++++++++++ C++/典型实现/4 复数类.md | 72 +++++++ C++/典型实现/5 时间类.md | 197 ++++++++++++++++++ C++/典型实现/6 LRU算法.md | 78 +++++++ C++/{CMake.md => 编译调试/CMake编译.md} | 0 C++/编译调试/g++.md | 0 C++/编译调试/gdb调试.md | 0 C++/test.cpp => code_segment/binary_tree.cpp | 0 {C++/代码片段 => code_segment}/test.cpp | 0 {C++/代码片段 => code_segment}/test2.cpp | 0 {C++/代码片段 => code_segment}/test_delim.cpp | 0 {C++/代码片段 => code_segment}/test_input.cpp | 0 工作日志/2021年8月3日-八月份计划.md | 1 + 数据库/Redis/04 数据库.md | 4 +- 数据库/Redis/05 生命周期.md | 2 +- 18 files changed, 719 insertions(+), 11 deletions(-) delete mode 100644 C++/mianshi.cpp create mode 100644 C++/典型实现/1 内存分配器.md create mode 100644 C++/典型实现/2 智能指针.md create mode 100644 C++/典型实现/3 字符串类.md create mode 100644 C++/典型实现/4 复数类.md create mode 100644 C++/典型实现/5 时间类.md create mode 100644 C++/典型实现/6 LRU算法.md rename C++/{CMake.md => 编译调试/CMake编译.md} (100%) create mode 100644 C++/编译调试/g++.md create mode 100644 C++/编译调试/gdb调试.md rename C++/test.cpp => code_segment/binary_tree.cpp (100%) rename {C++/代码片段 => code_segment}/test.cpp (100%) rename {C++/代码片段 => code_segment}/test2.cpp (100%) rename {C++/代码片段 => code_segment}/test_delim.cpp (100%) rename {C++/代码片段 => code_segment}/test_input.cpp (100%) diff --git a/C++/mianshi.cpp b/C++/mianshi.cpp deleted file mode 100644 index ff9a549d..00000000 --- a/C++/mianshi.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include -using namespace std; - -int main(){ - int b =1; - return 0; -} \ No newline at end of file diff --git a/C++/典型实现/1 内存分配器.md b/C++/典型实现/1 内存分配器.md new file mode 100644 index 00000000..4e600e89 --- /dev/null +++ b/C++/典型实现/1 内存分配器.md @@ -0,0 +1,107 @@ +```C++ +#ifndef __JJALLOC__ +#define __JJALLOC__ +#endif +#include // for placement new +#include //for cerr +#include //for ptrdiff_t +#include // for exit() +#include // for UINT_MAX +namespace my{ + // 申请内存空间。调用operator new 。 + // T*参数是为了注册模板类型T + template + inline T* _allocate(ptrdiff_t size, T*){ + //set_new_handler(0); + T* tmp = (T*)(::operator new)((size_t)(size * sizeof(T))); + if (tmp == 0){ + std::cerr << "out of memory" << std::endl; + } + return tmp; + } + + // 释放内存空间。调用operator delete + template + inline void _deallocate(T* buffer){ + ::operator delete(buffer); + } + + // 创建内存对象。调用placement new + template + inline void _construct(T1 *p, const T2 &value){ + new (p)T1(value); + } + // 通过查询了解到这个操作叫做placement new,就是在指针p所指向的内存空间创建一个T1类型的对象,但是对象的内容是从T2类型的对象转换过来的(调用了T1的构造函数,T1::T1(value))。 + // 就是在已有空间的基础上重新调整分配的空间,类似于realloc函数。这个操作就是把已有的空间当成一个缓冲区来使用,这样子就减少了分配空间所耗费的时间,因为直接用new操作符分配内存的话,在堆中查找足够大的剩余空间速度是比较慢的。 + + // 释放内存对象。调用析构函数。 + template + inline void _destroy(T* ptr){ + ptr->~T(); + } + + + template + class allocate{ + public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + // template + // struct rebind{ + // typedef allocator other; + // }; + + pointer alloc(size_type n, const void * hint = 0){ + return _allocate((difference_type)n, (pointer)0); + } + void deallocate(pointer p, size_type n){ + _deallocate(p); + } + + void construct(pointer p, const_reference value){ + return _construct(p, value); + } + + void destroy(pointer p){ + _destroy(p); + } + pointer address(reference x){ + return (pointer)&x; + } + pointer const_address(const_reference x){ + return (const_pointer)&x; + } + + size_type max_size()const{ + return (size_type)(UINT_MAX / sizeof(T)); + } + }; +} +#include +using namespace std; +int main(){ + my::allocate al; + int * ptr = al.alloc(10); + cout<<"alloc:"<<*ptr<<"\t"<<*(ptr+1)< +class SmartPtr +{ +private: + T *ptr; //底层真实的指针 + + int *use_count; //保存当前对象被多少指针引用计数 + +public: + SmartPtr(T *p); //SmartPtrp(new int(2)); + + SmartPtr(const SmartPtr &orig); //SmartPtrq(p); + + SmartPtr &operator=(const SmartPtr &rhs); //q=p + + ~SmartPtr(); + + T operator*(); //为了能把智能指针当成普通指针操作定义解引用操作 + + T *operator->(); //定义取成员操作 + + T *operator+(int i); //定义指针加一个常数 + + int operator-(SmartPtr &t1); //定义两个指针相减。当定义成友元函数的时候,必须有两个参数。当定义成类的成员函数的时候。相当于调用函数,智能有一个参数。 + + int getcount() { return *use_count; }; +}; + + +template +int SmartPtr::operator-(SmartPtr &t) { + return ptr - t.ptr; + } + +template +SmartPtr::SmartPtr(T *p) +{ + ptr = p; + try + { + use_count = new int(1); + } + catch (...) + { + delete ptr; //申请失败释放真实指针和引用计数的内存 + + ptr = nullptr; + delete use_count; + use_count = nullptr; + } +} +template +SmartPtr::SmartPtr(const SmartPtr &orig) //复制构造函数 + +{ + + use_count = orig.use_count; //引用计数保存在一块内存,所有的SmarPtr对象的引用计数都指向这里 + + this->ptr = orig.ptr; + + ++(*use_count); //当前对象的引用计数加1 +} +template +SmartPtr &SmartPtr::operator=(const SmartPtr &rhs) +{ + //重载=运算符,例如SmartPtrp,q; p=q;这个语句中,首先给q指向的对象的引用计数加1,因为p重新指向了q所指的对象,所以p需要先给原来的对象的引用计数减1,如果减一后为0,先释放掉p原来指向的内存,然后讲q指向的对象的引用计数加1后赋值给p + + ++*(rhs.use_count); + if ((--*(use_count)) == 0) + { + delete ptr; + ptr = nullptr; + delete use_count; + use_count = nullptr; + } + ptr = rhs.ptr; + *use_count = *(rhs.use_count); + return *this; +} +template +SmartPtr::~SmartPtr() +{ + getcount(); + if (--(*use_count) == 0) //SmartPtr的对象会在其生命周期结束的时候调用其析构函数,在析构函数中检测当前对象的引用计数是不是只有正在结束生命周期的这个SmartPtr引用,如果是,就释放掉,如果不是,就还有其他的SmartPtr引用当前对象,就等待其他的SmartPtr对象在其生命周期结束的时候调用析构函数释放掉 + + { + getcount(); + delete ptr; + ptr = nullptr; + delete use_count; + use_count = nullptr; + } +} +template +T SmartPtr::operator*() +{ + return *ptr; +} +template +T *SmartPtr::operator->() +{ + return ptr; +} +template +T *SmartPtr::operator+(int i) +{ + T *temp = ptr + i; + return temp; +} + +#include +using namespace std; +int main(){ + SmartPtr ptr(new int(123)); + cout<<*ptr<> 运算符 +* 6. 重载比较运算符 +* 7. 重载[]下标运算符 +*/ + +#include +#include +using namespace std; + +class MyString +{ +private: + char * str; + int length; +public: + // 长度 + int size ()const { + return length; + }; + char* getstr()const{ + return str; + } + // 默认构造函数 + MyString(); + // 字符串构造函数 + MyString(const char*); + // 复制构造函数 + MyString(const MyString& b); + + // 重载等号运算符 + MyString& operator=(const MyString &b); + // 重载+=运算符 + MyString& operator+=(const MyString &b); + // 重载比较运算符 + bool operator<(const MyString &b); + // 重载下标运算符 + char& operator[](const int &index) const ; + // 重载输入输出操作 + friend ostream& operator<<(ostream& ,const MyString &b); + ~MyString(); +}; + +MyString::MyString() +{ + str = new char[1]; + str[0]='\0'; + length = 0; +} + +MyString::MyString(const char* b){ + if(b){ + length = strlen(b); + str = new char[length+1]; + strcpy(str,b); + } + else{ + MyString(); + } +} +MyString::MyString(const MyString&b){ + length = b.size(); + if(length>0) + str = new char[length+1]; + else + MyString(); +} + +MyString& MyString::operator=(const MyString &b){ + if(&b == this){ + return *this; + } + delete[] str; + length = b.size(); + str = new char[length + 1]; + strcpy(str,b.getstr()); + return *this; +} + +MyString& MyString::operator+=(const MyString&b){ + if(b.size()==0){ + return *this; + } + char* temp = new char[length+b.length+1]; + strcpy(temp,str); + strcat(temp,b.getstr()); + delete[] str; + str = temp; + return *this; +} + +char& MyString::operator[](const int &index)const { + if(index>length)return str[length]; + return str[index]; +} + +bool MyString::operator<(const MyString &b){ + for(int i=0;ib.size())return false; + if(b[i]>str[i])return true; + if(b[i] +using namespace std; +class complex{ +public: + complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag){ }; +public: + friend complex operator+(const complex & A, const complex & B); + friend complex operator-(const complex & A, const complex & B); + friend complex operator*(const complex & A, const complex & B); + friend complex operator/(const complex & A, const complex & B); + friend istream & operator>>(istream & in, complex & A); + friend ostream & operator<<(ostream & out, complex & A); +private: + double m_real; //实部 + double m_imag; //虚部 +}; +//重载加法运算符 +complex operator+(const complex & A, const complex &B){ + complex C; + C.m_real = A.m_real + B.m_real; + C.m_imag = A.m_imag + B.m_imag; + return C; +} +//重载减法运算符 +complex operator-(const complex & A, const complex &B){ + complex C; + C.m_real = A.m_real - B.m_real; + C.m_imag = A.m_imag - B.m_imag; + return C; +} +//重载乘法运算符 +complex operator*(const complex & A, const complex &B){ + complex C; + C.m_real = A.m_real * B.m_real - A.m_imag * B.m_imag; + C.m_imag = A.m_imag * B.m_real + A.m_real * B.m_imag; + return C; +} +//重载除法运算符 +complex operator/(const complex & A, const complex & B){ + complex C; + double square = A.m_real * A.m_real + A.m_imag * A.m_imag; + C.m_real = (A.m_real * B.m_real + A.m_imag * B.m_imag)/square; + C.m_imag = (A.m_imag * B.m_real - A.m_real * B.m_imag)/square; + return C; +} +//重载输入运算符 +istream & operator>>(istream & in, complex & A){ + in >> A.m_real >> A.m_imag; + return in; +} +//重载输出运算符 +ostream & operator<<(ostream & out, complex & A){ + out << A.m_real <<" + "<< A.m_imag <<" i ";; + return out; +} +int main(){ + complex c1, c2, c3; + cin>>c1>>c2; + c3 = c1 + c2; + cout<<"c1 + c2 = "< +#include "mytime.h" + +using namespace std; + +//-------默认构造函数 +Time::Time() +{ + hours = mintues = 0; + cout << "调用默认构造函数" << endl; +} + +//------显式的构造函数 +Time::Time(int h, int m) :hours(h), mintues(m) +{ + cout << "调用显式构造函数" << endl; +} + +//------拷贝构造函数 +Time::Time(const Time &t) +{ + hours = t.hours; + mintues = t.mintues; + cout << "调用拷贝构造函数" << endl; +} + +//------析构函数 +Time::~Time() +{ + cout << "调用了析构函数" << endl; +} + +//-------小时相加 +void Time::AddHour(int h) +{ + hours += h; +} + +//------分钟相加 +void Time::AddMin(int m) +{ + mintues += m; + hours += mintues / 60; + mintues %= 60; +} + + +//------重载+号 +Time Time::operator+(const Time &t) const +{ + Time sum; + sum.mintues = mintues + t.mintues; + sum.hours = hours + t.hours + sum.mintues / 60; + sum.mintues = sum.mintues % 60; + return sum; +} + +//------重载-号 +Time Time::operator-(const Time &t) const +{ + Time diff; + + int time1 = hours * 60 + mintues; + int time2 = t.hours * 60 + t.mintues; + + diff.hours = (time1 - time2) / 60; + diff.mintues = (time1 - time2) % 60; + + return diff; +} + +//-------重载乘号 +Time Time::operator*(double n) const +{ + Time result; + long totalMintues = n*hours * 60 + n*mintues; + + result.hours = totalMintues / 60; + result.mintues = totalMintues % 60; + + return result; +} + + + +//-------友元输出操作符 +ostream & operator<<(ostream &os, const Time &t) //友元在类外定义的时候,不需要添加friend; +{ + os << "hours:" << t.hours << " " << "mintues:" << t.mintues << " "; + return os; +} + +//----------------------- +//main.cpp +//不用先生 +//------------------------ +#include +#include "mytime.h" + +using namespace std; + + +int main() +{ + + { + Time eat_breakfast(0, 45); + Time eat_lunch(1, 0); + Time eat_dinner(1, 30); + + + + Time swiming(0, 45); //非const对象,既可以调用const成员函数,也可以调用非const成员。 + const Time study(8, 5); //const对象只能调用const成员函数。 + + + // study_cut_swim; + Time study_cut_swim = study - swiming; //调用运算符重载后的Time类的减号; + + + Time Eat_time_day = eat_breakfast + eat_dinner + eat_lunch; //调用了重载以后的加法; + + cout << "学习比游泳多花" << study_cut_swim << endl; //调用友元输出运算符<< + cout << "每周吃饭所花费的时间为" << (7 * Eat_time_day) << endl; //调用了友元乘法以及输出运算符; + } + + + + system("pause"); + return 0; +} +``` + diff --git a/C++/典型实现/6 LRU算法.md b/C++/典型实现/6 LRU算法.md new file mode 100644 index 00000000..9f75ce7c --- /dev/null +++ b/C++/典型实现/6 LRU算法.md @@ -0,0 +1,78 @@ +## lru最近最少使用算法 + +* 使用std::list<>双向链表存储value,主要是符合LRU的业务场景:①首/尾进行插入、删除;②中间位置的删除。其中第②点很重要。 +* 使用std::unordered_map<>是为了优化查找。此数据结构查找效率O(1)。 +* 注意对链表std::list<>的earse操作,特别是迭代器失效的问题。 + +```C++ +// 最近最少缓存算法(key,value) +class LRUCache +{ +private: + // 1、list双向链表 + std::list > _list; + + // 2、使用unordered_map + // 由于需要快速定位链表的结点,故在map中使用value字段来存储链表的结点,这里是使用了迭代器。 + std::unordered_map< int, std::list>::iterator > _map; + unsigned int _capacity; +public: + LRUCache(unsigned int capacity):_capacity(capacity) + { + } + // 获取 + int get(int key); + // 设置 + void set(int key, int value); +}; + + +// 设置 +void LRUCache::set(int key, int value) +{ + // 1、查询是否在缓存中 + auto iteramap = _map.find(key); + if(iteramap != _map.end()){ + // 2、在缓存中,需要在链表中擦除。 + _list.erase(iteramap->second); + // 3、把数据放到链表头 + _list.push_front(std::pair(key, value)); + _map[key] = _list.begin(); + }else{ + if(_map.size() >= _capacity){ + // 4、缓存已经满了 + // 4.1 hash处要删除 + _map.erase(_list.back().first); + // 4.2 链表也要删除尾巴部分 + _list.pop_back(); + } + // 5、双向链表首结点插入 + _list.push_front(std::pair(key, value)); + // 6、在hash中增加 + _map[key] = _list.begin(); + } +} + + +// 获取:根据key,获取缓存的value +int LRUCache::get(int key) +{ + // 1、先从hash中查找 + auto iteramap = _map.find(key); + if(iteramap == _map.end()){ + // 没找到,TODO + return -1; + } + // 2、如果在缓存中,需要把数据放到链表头部。 + _list.push_front(std::pair(key, iteramap->second->second)); + _list.erase(iteramap->second); + + // 3、hash原来存储的失效,需要重新设置 + _map[key] = _list.begin(); + + // 4、返回value值 + return iteramap->second->second; +} +``` + + diff --git a/C++/CMake.md b/C++/编译调试/CMake编译.md similarity index 100% rename from C++/CMake.md rename to C++/编译调试/CMake编译.md diff --git a/C++/编译调试/g++.md b/C++/编译调试/g++.md new file mode 100644 index 00000000..e69de29b diff --git a/C++/编译调试/gdb调试.md b/C++/编译调试/gdb调试.md new file mode 100644 index 00000000..e69de29b diff --git a/C++/test.cpp b/code_segment/binary_tree.cpp similarity index 100% rename from C++/test.cpp rename to code_segment/binary_tree.cpp diff --git a/C++/代码片段/test.cpp b/code_segment/test.cpp similarity index 100% rename from C++/代码片段/test.cpp rename to code_segment/test.cpp diff --git a/C++/代码片段/test2.cpp b/code_segment/test2.cpp similarity index 100% rename from C++/代码片段/test2.cpp rename to code_segment/test2.cpp diff --git a/C++/代码片段/test_delim.cpp b/code_segment/test_delim.cpp similarity index 100% rename from C++/代码片段/test_delim.cpp rename to code_segment/test_delim.cpp diff --git a/C++/代码片段/test_input.cpp b/code_segment/test_input.cpp similarity index 100% rename from C++/代码片段/test_input.cpp rename to code_segment/test_input.cpp diff --git a/工作日志/2021年8月3日-八月份计划.md b/工作日志/2021年8月3日-八月份计划.md index 0ca1be49..c8e6a400 100644 --- a/工作日志/2021年8月3日-八月份计划.md +++ b/工作日志/2021年8月3日-八月份计划.md @@ -15,6 +15,7 @@ * [x] 设计模式 * [ ] 并行编程 * [ ] GO + * [x] 重新整理go知识(在原先的基础上进行了扩充) * [ ] 基础知识。 * [ ] go语言的优势。 * [ ] 协程并发编程等,相关内容的了解。 diff --git a/数据库/Redis/04 数据库.md b/数据库/Redis/04 数据库.md index a9f25454..0dcd73cc 100644 --- a/数据库/Redis/04 数据库.md +++ b/数据库/Redis/04 数据库.md @@ -242,7 +242,7 @@ typedef struct redisDb { 命令回复会保存在输出缓冲区,之后实现函数还会为套接字关联命令回复处理器,将回复返回给客户端。 -### 命令执行器(5):执行后续工作 +### 命令执行器(4):执行后续工作 - 如果开启了慢查询,添加新的日志。 - `redisCommand`结构的`calls`计数器+1。 @@ -390,7 +390,7 @@ struct redisServer { - 增加cronloops计数器(它的唯一作用就是复制模块中实现『每执行`serverCron`函数N次就执行一次指定代码』的功能”) -## 5 数据库通知功能 +## 5 服务器客户端通知过程 数据库通知是Redis 2.8新增加的功能,让客户端通过订阅可给定的频道或模式,来获取数据库中键的变化,以及数据库命令的执行情况。 diff --git a/数据库/Redis/05 生命周期.md b/数据库/Redis/05 生命周期.md index 4afe8907..45415683 100644 --- a/数据库/Redis/05 生命周期.md +++ b/数据库/Redis/05 生命周期.md @@ -12,7 +12,7 @@ Redis 可以为每个键设置过期时间,当键过期时,会自动删除 `EXPIRE`或`PEXPIRE`命令让客户端可以以秒或者毫秒进度为某个键设置生存时间。经过指定的时间后,服务器会自动删除生存时间为0的键。 -`EXPIREAT`或`PEXPIREAT`命令,以秒或毫秒精度为某个键设置过期时间,过期时间是一个UNIX时间戳。 +`EXPIREAT`或`PEXPIREAT`命令,以秒或毫秒精度为某个键设置过期时间,过期时间是一个UNIX时间戳。 `TTL`和`PTTL`命令可查看某个键的剩余生存时间。