目录
1. 模板
1.0 函数模板
1.1 类模板
2. 顺序容器
2.0 vector容器
2.1 list容器
2.2 deque容器
2.3 string容器
3. 容器适配器
4. 关联容器
5. 智能指针
5.0 独享指针unique_ptr
5.2 弱指针weak_ptr
5.3 环状引用问题
样式示例如下
template
void Test(const T &t)
{
T t1 = t;
cout << t1 << endl;
}
样式示例如下
template
class Test
{
private:
T * _data;
public:
Test(int size)
{
_data = new T[size];
}
};
vector容器在堆空间建立一个一维的数组,地址空间时连续的,在vector中删除和插入元素时效率低,原因是在删除或插入时后面的元素会向前或向后移动。
int main()
{
vectorv1;
vectorv2(10); //指定大小
vectorv3(10, -1); //指定大小和元素初始值
}
vector相关函数的使用
int main()
{
vectorv; //定义
for (int i = 0; i < 10;i++)
{
v.push_back(i + 1); //添加
cout << v.size() << '\t' << v.capacity() << endl; //size函数和capacity函数
}
for (vector::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl; //迭代器访问
}
v.resize(5); //强制调整元素大小(个数)
cout << v.size() << '\t' << v.capacity() << endl; //此时size : 5 ,capacity : 13
for (vector::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl; //只能访问到了前5个元素
}
v.reserve(100); //手动改变空间大小
cout << v.size() << '\t' << v.capacity() << endl; //此时size : 5 ,capacity : 100
v.shrink_to_fit(); //回收未使用空间
cout << v.size() << '\t' << v.capacity() << endl; //此时size : 5 ,capacity : 5}
本质是一个双向链表,支持快速的插入和删除,不支持快速访问,只能从表头开始访问。
list与vector操作上大同小异,只不过其底层实现不同而已,不过list中并没有capacity的概念,所以没有其相关函数,示例如下
int main()
{
listv; //定义
for (int i = 0; i < 10;i++)
{
v.push_back(i + 1); //添加
cout << v.size() << '\t' << endl; //size函数
}
for (list::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl; //迭代器访问
}
v.resize(5); //强制调整元素大小(个数)
cout << v.size() << '\t' << endl; //此时size : 5
for (list::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl; //只能访问到了前5个元素
}}
deque容器本质是一种双端队列,看狭义的看成是线性结构,所谓双端是指在队列头和队列尾都可进行删除和插入操作。
int main()
{
dequev; //定义
for (int i = 0; i < 5;i++)
v.push_front(i + 1); //对头插入
for (int i = 5; i < 10;i++)
v.push_back(i + 1); //对尾插入
//经过上述两步插入 此时队列中数据呈现这样的形态: [5,4,3,2,1,6,7,8,9,10]
//注意队列是先进先出的线性结构,双端队列同样。
for (deque::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl; //迭代器访问
}
v.resize(5); //强制调整元素大小(个数)
cout << v.size() << '\t' << endl; //此时size : 5
for (deque::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl; //只能访问到了前5个元素
}
v.shrink_to_fit(); //deque容器并未提供capacity函数,不过这无关紧要。
}
可以看成是专门处理char型的vector容器,其提供了丰富的字符串处理函数。
容器适配器将原来的容器进行了一层封装。底层是普通容器,上层对外提供封装后的新接口。
常用的栈stack、队列queue和优先队列priority_queue在STL中都有自己的容器适配器。使用方法如下:
int main()
{
//栈
stacks; //默认使用deque
stack> s1; //指定使用vector
//队列
queueq; //默认使用deque
queue> q1; //指定使用list
//优先队列
priority_queuep; //默认使用vector
priority_queue> p1; //指定使用deque
priority_queue, cmp >> p2; //指定使用vector和权重比较函数cmp
}
自定义优先队列的元素权重函数
class Square
{
public:
int length;
int width;
Square(int l, int w):length(l),width(w){}
};class Compare
{
public:
bool operator() (Square x, Square y)
{
return ((x.length * x.width) < (y.length * y.width));
}
};int main()
{
priority_queue, Compare > p;
for (int i = 0; i < 10; i++)
p.push(Square(rand() % 100 + 1, rand() % 100 + 1));while (!p.empty())
{
cout << p.top().length << "*" << p.top().width <<'\t'<< p.top().length * p.top().width << endl;
p.pop();
}
}
STL中关联容器有四种:set、map、multiset和multimap.最常用的是前两种。
map中保存着一系列的键值对。键具有唯一性。可以使用下标访问符访问map中元素。map的下标是键,返回的是该键对应的值,也可以通过下标操作符给map添加元素。
map中元素是一系列键值对,每个键值对是pair类型。可以创建一个pair类型的变量并添加到map中,pair的第一个元素作为map元素的键,第二个元素作为map元素的值。可以通过first和second访问pair中的元素。具体操作如下
int main()
{
pairp("sssss", 22);
string s = p.first;
int i = p.second;
mapm;
m.insert(p);
cout << m[s] << endl;
}
set中每个元素只包含一个键,并且set键具有唯一性
智能指针的本质是一个类模板,对普通的指针进行了一层封装,模板参数是指针指向的类型,通过重载->和*两个操作符使智能指针与普通指针用法相同。
C++常用的三个智能指针分别是:unique_ptr独享指针、shared_ptr共享指针和weak_ptr弱指针。
独享指针unique_ptr唯一拥有所指向对象的所有权,不支持拷贝和赋值操作。因此不能用unique_ptr对另一个智能指针初始化或赋值,而只能通过move函数将其所有权转移给其他智能指针,确保不和其他智能指针指向同一个对象。
class Test
{
private:
int _x;
public:
Test(int t):_x(t) {}
int getX() const { return _x; }
};int main()
{
unique_ptrp(new Test(12));
cout << p->getX() << endl;
//unique_ptrp1 = p; //错误
unique_ptrp2 = move(p); //正确
cout << p2->getX() << endl;
}
作为最为常见的指针,多个shared_ptr共享所指向对象的所有权,通过引用计数器管理指向同意对象的指针个数。每增加一个智能指针指向对想,引用计数器就加一,当指向同意对象的所有智能指针生命周期全部结束时,引用计数器为0,此时释放对象空间。
class Test
{
private:
int _x;
public:
Test(int t):_x(t) {}
int getX() const { return _x; }
~Test() { cout << "destory Test! " << endl; }
};int main()
{
shared_ptrp(new Test(12));
shared_ptrp1 = p;
cout << p->getX() << endl; //输出_x值为12
cout << p1.use_count() << endl; //输出引用计数值为2
p.reset();
cout << p1.use_count() << endl; //输出引用计数值为1
}
弱指针一般配合共享指针一起使用,weak_ptr可以和shared_ptr指向同一个对象,但是不改变引用计数器的值。
两个shared_ptr指针所指对象的数据成员中,如果含有指向对方对象的share_ptr指针,则会产生环状引用。
class B;
class A
{
public:
shared_ptr bptr;
~A() { cout << "~ A ()" << endl; }
};
class B
{
public:
shared_ptr aptr;
~B() { cout << "~B()" << endl; }
};int main()
{
shared_ptr a(new A());
shared_ptr b(new B());a->bptr = b;
b->aptr = a;
}
程序中通过创建了一个类A的对象的一个类B的对想,并通过shared_ptr指向他们,之后通过指向另一个对象的智能指针对自身的数据成员ptr进行赋值,因此两个对象的引用计数器都为2.
当程序退出时,main函数创建的智能指针生命周期结束,其所指向的对象引用计数减1,由于环状引用,对象内部的生命周期都不会结束,两个对象引用计数始终未1.
具体来讲,对象A中的智能指针bptr只有在对象A析构之后才会结束,从而将对象B的引用计数减1,但对象A并不会销毁,因为A销毁的条件是指向A的智能指针计数为0,而对象B中指向A的指针只有在B析构之后销毁,这是一个逻辑上的死结。
解决的方法是应用weak_ptr, 重写代码如下:
class B;
class A
{
public:
weak_ptr bptr;
~A() { cout << "~ A ()" << endl; }
};
class B
{
public:
weak_ptr aptr;
~B() { cout << "~B()" << endl; }
};int main()
{
shared_ptr a(new A());
shared_ptr b(new B());a->bptr = b;
b->aptr = a;
}