C++典型实现补充

This commit is contained in:
Estom
2021-09-03 06:42:58 +08:00
parent 2d9a1a3b53
commit 4922bbf1eb
18 changed files with 719 additions and 11 deletions

View File

@@ -1,8 +0,0 @@
#include<iostream>
#include<vector>
using namespace std;
int main(){
int b =1;
return 0;
}

View File

@@ -0,0 +1,107 @@
```C++
#ifndef __JJALLOC__
#define __JJALLOC__
#endif
#include<new> // for placement new
#include<iostream> //for cerr
#include<cstddef> //for ptrdiff_t
#include<cstdlib> // for exit()
#include<climits> // for UINT_MAX
namespace my{
// 申请内存空间。调用operator new 。
// T*参数是为了注册模板类型T
template<class T>
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<class T>
inline void _deallocate(T* buffer){
::operator delete(buffer);
}
// 创建内存对象。调用placement new
template<class T1,class T2>
inline void _construct(T1 *p, const T2 &value){
new (p)T1(value);
}
// 通过查询了解到这个操作叫做placement new就是在指针p所指向的内存空间创建一个T1类型的对象但是对象的内容是从T2类型的对象转换过来的调用了T1的构造函数T1::T1(value))。
// 就是在已有空间的基础上重新调整分配的空间类似于realloc函数。这个操作就是把已有的空间当成一个缓冲区来使用这样子就减少了分配空间所耗费的时间因为直接用new操作符分配内存的话在堆中查找足够大的剩余空间速度是比较慢的。
// 释放内存对象。调用析构函数。
template<class T>
inline void _destroy(T* ptr){
ptr->~T();
}
template <class T>
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<class U>
// struct rebind{
// typedef allocator<U> 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<iostream>
using namespace std;
int main(){
my::allocate<int> al;
int * ptr = al.alloc(10);
cout<<"alloc:"<<*ptr<<"\t"<<*(ptr+1)<<endl;
al.construct(ptr,123);
cout<<"construct:"<<*ptr<<"\t"<<*(ptr+1)<<endl;
al.destroy(ptr);
cout<<"destroy:"<<*ptr<<"\t"<<*(ptr+1)<<endl;
al.deallocate(ptr,100);
cout<<"deallocate:"<<*ptr<<"\t"<<*(ptr+1)<<endl;
int size = al.max_size();
cout<<"size:"<<size<<endl;
int* b=new int[3];
cout<<*b<<endl;
new (b)int(999);
cout<<*b<<endl;
cout<<*(b+1)<<endl;
}
```

View File

@@ -0,0 +1,119 @@
```C++
template <typename T>
class SmartPtr
{
private:
T *ptr; //底层真实的指针
int *use_count; //保存当前对象被多少指针引用计数
public:
SmartPtr(T *p); //SmartPtr<int>p(new int(2));
SmartPtr(const SmartPtr<T> &orig); //SmartPtr<int>q(p);
SmartPtr<T> &operator=(const SmartPtr<T> &rhs); //q=p
~SmartPtr();
T operator*(); //为了能把智能指针当成普通指针操作定义解引用操作
T *operator->(); //定义取成员操作
T *operator+(int i); //定义指针加一个常数
int operator-(SmartPtr<T> &t1); //定义两个指针相减。当定义成友元函数的时候,必须有两个参数。当定义成类的成员函数的时候。相当于调用函数,智能有一个参数。
int getcount() { return *use_count; };
};
template <typename T>
int SmartPtr<T>::operator-(SmartPtr<T> &t) {
return ptr - t.ptr;
}
template <typename T>
SmartPtr<T>::SmartPtr(T *p)
{
ptr = p;
try
{
use_count = new int(1);
}
catch (...)
{
delete ptr; //申请失败释放真实指针和引用计数的内存
ptr = nullptr;
delete use_count;
use_count = nullptr;
}
}
template <typename T>
SmartPtr<T>::SmartPtr(const SmartPtr<T> &orig) //复制构造函数
{
use_count = orig.use_count; //引用计数保存在一块内存所有的SmarPtr对象的引用计数都指向这里
this->ptr = orig.ptr;
++(*use_count); //当前对象的引用计数加1
}
template <typename T>
SmartPtr<T> &SmartPtr<T>::operator=(const SmartPtr<T> &rhs)
{
//重载=运算符例如SmartPtr<int>p,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 <typename T>
SmartPtr<T>::~SmartPtr()
{
getcount();
if (--(*use_count) == 0) //SmartPtr的对象会在其生命周期结束的时候调用其析构函数在析构函数中检测当前对象的引用计数是不是只有正在结束生命周期的这个SmartPtr引用如果是就释放掉如果不是就还有其他的SmartPtr引用当前对象就等待其他的SmartPtr对象在其生命周期结束的时候调用析构函数释放掉
{
getcount();
delete ptr;
ptr = nullptr;
delete use_count;
use_count = nullptr;
}
}
template <typename T>
T SmartPtr<T>::operator*()
{
return *ptr;
}
template <typename T>
T *SmartPtr<T>::operator->()
{
return ptr;
}
template <typename T>
T *SmartPtr<T>::operator+(int i)
{
T *temp = ptr + i;
return temp;
}
#include<iostream>
using namespace std;
int main(){
SmartPtr<int> ptr(new int(123));
cout<<*ptr<<endl;
return 0;
}
```

View File

@@ -0,0 +1,142 @@
## 4 实例——MyString的实现
```C++
/*
* C++ string 类的实现
* 1. 构造函数和析构函数
* 2. 字符串长度
* 3. 重载=运算符
* 4. 重载+=运算符
* 5. 重载<< >> 运算符
* 6. 重载比较运算符
* 7. 重载[]下标运算符
*/
#include <iostream>
#include <cstring>
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;i<length;i++){
if(i>b.size())return false;
if(b[i]>str[i])return true;
if(b[i]<str[i])return false;
}
return true;
}
MyString::~MyString()
{
delete[] str;
}
// 外部定义一个函数,内部声明为友元
ostream& operator<<(ostream &out,const MyString&b){
out<<b.getstr();
return out;
}
int main()
{
// 测试函数
MyString s1,s2="123",s3,s4="456";
s3=s2;
s1=s2;
s1+=s1;
cout<<s1<<endl;
cout<<s2<<endl;
cout<<s3<<endl;
cout<<(s3<s4)<<endl;
cout<<endl;
return 0;
}
```

View File

@@ -0,0 +1,72 @@
## 5 实例——complex的实现
```C++
#include <iostream>
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 = "<<c3<<endl;
c3 = c1 - c2;
cout<<"c1 - c2 = "<<c3<<endl;
c3 = c1 * c2;
cout<<"c1 * c2 = "<<c3<<endl;
c3 = c1 / c2;
cout<<"c1 / c2 = "<<c3<<endl;
return 0;
}
```

View File

@@ -0,0 +1,197 @@
## 6 实例——MyTime的实现
```C++
//------mytime.h
#ifndef MYTIME_H
#define MYTIME_H
#include <iostream>
using namespace std;
class Time
{
//----------私有成员,类中的成员默认是私有的
private:
int hours;
int mintues;
//----------共有成员
public:
Time(); //默认构造函数
Time(int h, int m = 0); //显式构造函数
Time(const Time &); //拷贝构造函数
~Time(); //析构函数
void AddMin(int m);
void AddHour(int h);
void reset(int h = 0, int m = 0);
//------展示函数show()
void Time::show() const
{
cout << "hours:" << hours << " " << "mintues:" << mintues << " ";
}
Time operator+(const Time &t) const; //运算符重载
Time operator-(const Time &t) const;
Time operator*(double n) const;
friend Time operator*(double n, const Time &t) //友元;
{
return t*n; //在这里又调用了重载运算符 operator*(double n) const
} //内联形式的定义;
friend ostream & operator<<(ostream &os, const Time &t); //一个双目运算符在重载时,如果是以友元的形式声明的,那么他有两个形参;如果是类的成员函数,那么他只有一个形参;
};
//-------时间重置,内联函数
inline void Time::reset(int h, int m)
{
hours = h;
mintues = m;
}
#endif
//--mytime.cpp
#include <iostream>
#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 <iostream>
#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;
}
```

View File

@@ -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<std::pair< int, int> > _list;
// 2、使用unordered_map
// 由于需要快速定位链表的结点故在map中使用value字段来存储链表的结点这里是使用了迭代器。
std::unordered_map< int, std::list<std::pair<int, int>>::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<int, int>(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<int, int>(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<int, int>(key, iteramap->second->second));
_list.erase(iteramap->second);
// 3、hash原来存储的失效需要重新设置
_map[key] = _list.begin();
// 4、返回value值
return iteramap->second->second;
}
```

0
C++/编译调试/g++.md Normal file
View File

View File

View File

@@ -15,6 +15,7 @@
* [x] 设计模式
* [ ] 并行编程
* [ ] GO
* [x] 重新整理go知识在原先的基础上进行了扩充
* [ ] 基础知识。
* [ ] go语言的优势。
* [ ] 协程并发编程等,相关内容的了解。

View File

@@ -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新增加的功能,让客户端通过订阅可给定的频道或模式,来获取数据库中键的变化,以及数据库命令的执行情况。

View File

@@ -12,7 +12,7 @@ Redis 可以为每个键设置过期时间,当键过期时,会自动删除
`EXPIRE``PEXPIRE`命令让客户端可以以秒或者毫秒进度为某个键设置生存时间。经过指定的时间后服务器会自动删除生存时间为0的键。
`EXPIREAT``PEXPIREAT`命令以秒或毫秒精度为某个键设置过期时间过期时间是一个UNIX时间戳。
`EXPIREAT``PEXPIREAT`命令以秒或毫秒精度为某个键设置过期时间过期时间是一个UNIX时间戳。
`TTL``PTTL`命令可查看某个键的剩余生存时间。