90%的情况都是在使用无序容器。
函数模板可以不适用<int>它可以进行类型推演。
哈希统计。键、值。
进行哈希映射。大文件的东西分别放到小文件中。
对于服务器来说,磁盘会很大。
在两个文件中查重。
给了不看,和不给一样。
智能指针。
裸指针:直接*访问的指针。就是普通的指针。
例如:int* p=new int;//裸指针
裸指针的缺点:
1.必须手动释放资源。
2.由于程序逻辑的错误,导致释放资源的代码没有被执行到。
3.程序抛出异常,导致没有被调用。
智能指针:智能(不管程序运行发生了什么意外的情况,一定会帮用户释放掉。)
智能指针,开辟内存在栈上开,只要出了栈,资源一定会被释放。是一个类。
自己给智能指针提供*运算符的重载函数,实现类*。
对象调用自己的运算符重载函数。
常对象只能调用常方法。
为什么要给它提供这些运算符重载函数呢?就是为了使只能指针用起来和裸指针一样,就是想用智能指针来替代裸指针呢。
不带引用计数的智能指针。(不能解决对象的浅拷贝问题)(对象的拷贝构造和赋值时会出现问题)
#include <iostream>
using namespace std;
template<typename T>
class CSmartPtr
{
public:
CSmartPtr(T *ptr = NULL)
:mptr(ptr){}
~CSmartPtr(){ delete mptr; }
T& operator*()
{
return *mptr;
}
const T& operator*()const
{
return *mptr;
}
T* operator->()
{
return mptr;
}
T* operator->()const
{
return mptr;
}
private:
T *mptr;
};
class A
{
public:
void func(){ cout << "call A::func" << endl; }
};
int main(int argc, char* argv[])
{
CSmartPtr<int> ptr1(new int);
*ptr1 = 30;
cout << *ptr1 << endl;
const CSmartPtr<int> ptr2(new int(40));
cout << *ptr2 << endl;
CSmartPtr<A> ptr3(new A());
(*ptr3).func();
//ptr3.operator->(func());
//(ptr3.operator->())->func();
ptr3->func();
const CSmartPtr<A> ptr4(new A());
ptr4->func();
return 0;
}
让指针指向了堆上的资源。
给它提供自定义的拷贝构造函数。(浅拷贝)
智能指针智能的释放资源。
所有的智能指针都需要考虑浅拷贝问题。
#include <memory>//包含的c++中所有的智能指针。
提供了*号运算符的重载函数。
没有提供<<运算符的重载函数。
库中提供的智能指针,会把资源的所有权拿过来,原来的智能指针就置为NULL,全部失效了。
auto_ptr是第一个出现在c++库中的智能指针。
原来智能指针底层的指针都置为空了。
智能指针:带引用计数的智能指针、不带引用计数的智能指针。
堆资源只能用地址来表示。
无序的map。
随手将指针置为NULL是个好习惯。
哈希表虽然快,但也经不起多次遍历。
不希望外部用户看到的方法就声明成私有方法,只给内部提供服务。
静态成员方法要在类外初始化。
带引用计数的智能指针。
#include <iostream>
#include <memory> // 这个头文件中,包含了C++库所有的智能指针
#include <unordered_map>
using namespace std;
/*
专门用来统计资源的引用计数 void* int
*/
class ReferenceCount
{
public:
//给ptr指向的资源增加引用计数
void incRef(void *ptr)
{
refMap[ptr]++;
}
//给ptr指向的资源减少引用计数
int decRef(void *ptr)
{
unordered_map<void*, int>::iterator it = refMap.find(ptr);
if (it == refMap.end())
{
return 0;
}
else
{
if (it->second > 1)
{
--(it->second);
return it->second;
}
else
{
return 0;
}
}
}
private:
//map的key表示资源地址, value表示资源的引用计数
unordered_map<void*, int> refMap;
};
template<typename T>
class CSmartPtr
{
public:
CSmartPtr(T *ptr = NULL)
:mptr(ptr)
{
if (mptr != NULL)
{
incRef();
}
}
CSmartPtr(const CSmartPtr<T> &src)
:mptr(src.mptr)
{
if (mptr != NULL)
{
incRef();
}
}
CSmartPtr<T>& operator=(const CSmartPtr<T> &src)
{
if (this == &src)
return *this;
if (decRef() == 0)
{
delete mptr;
mptr = NULL;
}
mptr = src.mptr;
if (mptr != NULL)
{
incRef();
}
return *this;
}
~CSmartPtr()
{
if (decRef() == 0)
{
delete mptr;
mptr = NULL;
}
}
T& operator*()
{
return *mptr;
}
const T& operator*()const
{
return *mptr;
}
T* operator->()
{
return mptr;
}
T* operator->()const
{
return mptr;
}
private:
T *mptr;
//专门供智能指针,查看当前它所引用的资源的引用计数
static ReferenceCount refCnt;
void incRef() { refCnt.incRef(mptr); }
int decRef() { return refCnt.decRef(mptr); }
};
template<typename T>
ReferenceCount CSmartPtr<T>::refCnt;
class A
{
public:
void func() { cout << "call A::func" << endl; }
};
int main(int argc, char* argv[])
{
CSmartPtr<int> ptr1(new int);
*ptr1 = 30;
cout << *ptr1 << endl;
CSmartPtr<int> ptr2(ptr1);
}
线程安全的智能指针。
1.++、--都不是线程安全的。
2.容器的插入删除本身就不是线程安全的。
类的前置声明:class A ;
智能指针(可以直接改变引用计数)是不能放在堆上的。
强智能指针循环/交叉引用时造成资源无法释放。
怎么解决?=》弱智能指针。
一个资源都有一个引用计数。
弱智能指针,无法直接接触引用计数表。它通过强智能指针感受引用计数。
弱智能指针只能观察引用计数。而不能直接操作引用计数。
week_ptr<B> _ptrb;
定义资源的地方采用强智能指针,要和资源挂上钩。使用智能指针的地方全部使用弱智能指针。
share_ptr(强智能指针)和week_ptr(弱智能指针)。(库中提供的)
A的析构导致了A的成员对象的析构。
智能指针是单独的一块,非常重要的东西。
在加加减减的时候没有进行任何的线程安全处理。
咱们写的智能指针没有提供线程安全的处理。
share_ptr(强智能指针)和week_ptr(弱智能指针)。提供了线程安全的处理。
弱智能指针之所以没有直接指向资源,不能改变引用计数,是因为弱智能指针根本没有提供指向运算符的重载的函数。
指向对象的弱智能指针不能引用对象的成员方法。
弱智能指针把自己提升成强智能指针(lock)。在提升前,会先观察强智能指针的引用计数,如果已经为0则提升失败。
提升成功后资源的引用计数也会加一,防止强智能指针将资源析构掉。
单线程中程序是串行执行的。多线程中任务是并行执行的。