博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ stl容器详解
阅读量:6072 次
发布时间:2019-06-20

本文共 21080 字,大约阅读时间需要 70 分钟。

STL(标准模板库),是目前C++内置支持的library。它的底层利用了C++类模板和函数模板的机制,由三大部分组成:容器、算法和迭代器。

一、容器是STL中很重要的一种数据结构。常见的容器包括

1.vector容器

vector就是动态数组。在堆中分配内存,元素连续存放,有保留内存,如果减少大小后,内存也不会释放。

如果新值>当前大小时才会再分配内存。

它拥有一段连续的内存空间,并且起始地址不变,因此它能非常好的支持随即存取,即[]操作符,但由于它的内存空间是连续的,所以在中间进行插入和删除会造成内存块的拷贝。

当该数组后的内存空间不够时,需要重新申请一块足够大的内存并进行内存的拷贝。这些都大大影响了vector的效率。底层数据结构为数组 ,支持快速随机访问。

【vector总结】

需要经常随机访问请用vector

【vector的基本用法】

front()返回头部元素的引用,可以当左值

back()返回尾部元素的引用,可以当左值

push_back()添加元素,只能尾部添加

pop_back()移除元素,只能在尾部移除

int main(int argc, const char * argv[]) {        //定义一个vector容器    vector
v1; //插入元素(尾部插入) v1.push_back(1); v1.push_back(2); v1.push_back(3); //迭代器遍历打印 for (vector
::iterator it = v1.begin(); it != v1.end(); it++) { cout << *it << " "; } cout << endl; //修改头部元素的值(front()返回是引用,可以当左值) v1.front() = 44; //输出头部元素 cout<< "头部元素:" << v1.front() << endl; //修改尾部的值(back()返回是引用,可以当左值) v1.back() = 99; //输出尾部元素 cout << "尾部元素" << v1.back() <
::iterator it = v1.begin(); it != v1.end(); it++) { cout << *it << " "; } cout << endl; return 0;}复制代码

【vector的初始化】

vector有4种方式初始化,有直接初始化,也有通过拷贝构造函数初始化。

int main(int argc, const char * argv[]) {    //直接构造函数初始化    vector
v1; v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); //通过拷贝构造函数初始化 vector
v2 = v1; //使用部分元素来构造 vector
v3(v1.begin(), v1.begin() + 1); vector
v4(v1.begin(), v1.end()); //存放三个元素,每个元素都是9 vector
v5(3,9); return 0;}复制代码

【vector的遍历】

vector的遍历有多种方式,可以根据[]或者迭代器遍历。

  • []方式,如果越界或出现其他错误,不会抛出异常,可能会崩溃,可能数据随机出现

  • at方式,如果越界或出现其他错误,会抛出异常,需要捕获异常并处理

  • 迭代器提供了逆向遍历,可以通过迭代器来实现逆向遍历,当然上面两种方式也可以

int main(int argc, const char * argv[]) {        //创建vector    vector
v1; //插入元素 for (int i = 0; i < 10; i++) { v1.push_back(i); } //遍历-[]取值 for (int i = 0; i < v1.size(); i++) { cout << v1[i] << " "; } cout << endl; //遍历-at取值 for (int i = 0; i < v1.size(); i++) { cout << v1.at(i) << " "; } cout << endl; //遍历-迭代器遍历 for (vector
::iterator it = v1.begin(); it != v1.end(); it++) { cout << *it << " "; } cout << endl; //遍历-迭代器逆向遍历 for (vector
::reverse_iterator it = v1.rbegin(); it != v1.rend(); it++) { cout << *it << " "; } cout << endl; //测试越界 cout << "[]越界:" << v1[20] << endl; //不会抛出异常,可能会崩溃,可能会乱码 cout << "at越界:" << v1.at(20) << endl; //会抛出异常,需要捕获异常 return 0;}复制代码

【vector的push_back强化】

push_back是在当前vector的内存末尾拷贝元素进入容器。注意这个地方可能产生浅拷贝,所以容器中的对象要支持拷贝操作。另外,如果vector初始化了个数,而不初始化具体的值,push_back也只会在最后面追加。

int main(int argc, const char * argv[]) {    //初始化10个元素的容器    vector
v(10); //打印容器大小 cout << v.size() << endl; //push_back添加元素 v.push_back(100); //打印容器大小 cout << v.size() << endl; //遍历后的结果是 0 0 0 0 0 0 0 0 0 0 100 for (vector
::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; return 0;}复制代码

【vector的元素删除】

vector的删除,是根据位置进行删除,如果想要删除某个元素,需要找到当前元素的迭代器位置,再进行删除。

erase(iterator)函数,删除后会返回当前迭代器的下一个位置。

int main(int argc, const char * argv[]) {    //1 创建容器并初始化    vector
v1(10); for (int i = 0; i < v1.size(); i++) { v1[i] = i; } //2 区间删除 //--2.1 删除前3个元素 v1.erase(v1.begin(), v1.begin() + 3); //--2.2 删除指定位置的元素 v1.erase(v1.begin() +3); //3 根据元素的值进行删除,删除值为2的元素 v1.push_back(2); v1.push_back(2); vector
::iterator it = v1.begin(); while (it != v1.end()) { if (*it == 2) { it = v1.erase(it); //删除后,迭代器指针会执行下一个位置并返回。 }else{ it++; } } //4 遍历打印 for (vector
::iterator it = v1.begin(); it != v1.end(); it++) { cout << *it << " "; } cout << endl; return 0;}复制代码

【vector的插入元素】

vector提供了insert函数,结合迭代器位置插入指定的元素。如果迭代器位置越界,会抛出异常。

int main(int argc, const char * argv[]) {    //初始化vector对象    vector
v1(10); //在指定的位置插入元素10的拷贝 v1.insert(v1.begin() + 3, 10); //在指定的位置插入3个元素11的拷贝 v1.insert(v1.begin(), 3, 11); //遍历 for (vector
::iterator it = v1.begin(); it != v1.end(); it++) { cout << *it << " "; } cout << endl; return 0;}复制代码

2.list链表模型

list就是双向链表,在堆中存放,每个元素都是放在一块内存中,它的内存空间可以是不连续的,通过指针来进行数据的访问,这个特点使得它的随机存取变的非常没有效率,因此它没有提供[]操作符的重载。

但它可以以很好的效率支持任意地方的删除和插入。

list没有空间预留习惯,所以每分配一个元素都会从内存中分配,每删除一个元素都会释放它占用的内存.底层数据结构为双向链表,支持快速增删

【list总结】

如果你喜欢经常添加删除大对象的话,那么请使用list 要保存的对象不大,构造与析构操作不复杂,那么可以使用vector代替 list<指针>完全是性能最低的做法,这种情况下还是使用vector<指针>好,因为指针没有构造与析构,也不占用很大内存

【list的基本操作】

int main(int argc, const char * argv[]) {    //创建list对象    list
l; //尾部添加元素 for (int i = 0; i < 10; i++) { l.push_back(i); } //头部添加元素 l.push_front(111); //遍历 for (list
::iterator it = l.begin(); it != l.end(); it++) { cout << *it << " "; } cout << endl; //list不能随机访问 list
::iterator it = l.begin(); it++; it++; cout << *it <

【list的删除】

list提供了两个函数用来删除元素,分别是erase和remove。

erase是通过位置或者区间来删除,主要结合迭代器指针来操作

remove是通过值来删除

int main(int argc, const char * argv[]) {    //创建list对象    list
l; //添加数据 for (int i = 0; i < 10; i++) { l.push_back(i); } l.push_back(100); l.push_back(100); //删除头部元素 l.erase(l.begin()); //删除某个区间 list
::iterator it = l.begin(); it++; it++; it++; l.erase(l.begin(), it); //移除值为100的所有元素 l.remove(100); //遍历 for (list
::iterator it = l.begin(); it != l.end(); it++) { cout << *it << " "; } cout << endl; return 0;}复制代码

3.deque双端数组

[堆1] --> [堆2] -->[堆3] -->...

每个堆保存好几个元素,然后堆和堆之间有指针指向,看起来像是list和vector的结合品.

它支持[]操作符,也就是支持随机存取,可以让你在前面快速地添加删除元素,或是在后面快速地添加删除元素,然后还可以有比较高的随机访问速度,和vector的效率相差无几。

它支持在两端的操作:push_back,push_front,pop_back,pop_front等,并且在两端操作上与list的效率也差不多。

在标准库中vector和deque提供几乎相同的接口,在结构上它们的区别主要在于这两种容器在组织内存上不一样,deque是按页或块来分配存储器的,每页包含固定数目的元素.相反vector分配一段连续的内存,vector只是在序列的尾段插入元素时才有效率,而deque的分页组织方式即使在容器的前端也可以提供常数时间的insert和erase操作,而且在体积增长方面也比vector更具有效率

【deque操作】

  • push_back 从尾部插入元素
  • push_front 从头部插入元素
  • pop_back 从尾部删除元素
  • pop_front 从头部删除元素
  • distance函数可以求出当前的迭代器指针it距离头部的位置,也就是容器的指针,用法: distance(v1.begin(), it)
int main(int argc, const char * argv[]) {    //定义deque对象    deque
d1; //尾部插入元素 d1.push_back(10); d1.push_back(20); d1.push_back(30); //头部插入元素 d1.push_front(1); d1.push_front(2); d1.push_front(3); //尾部删除元素 d1.pop_back(); //头部删除元素 d1.pop_front(); //修改头部和尾部的值 d1.front() = 111; d1.back() = 222; //查找元素为1的下标 //通过distance求取下标 deque
::iterator it = d1.begin(); while (it != d1.end()) { if (*it == 1) { cout << "下标:" << distance(d1.begin(), it) << endl; } it++; } //遍历 for (deque
::iterator it = d1.begin(); it != d1.end(); it++) { cout << *it << " "; } cout << endl; return 0;}复制代码

【vector、list、deque总结】

vector是可以快速地在最后添加删除元素,并可以快速地访问任意元素

list是可以快速地在所有地方添加删除元素,但是只能快速地访问最开始与最后的元素

deque在开始和最后添加元素都一样快,并提供了随机访问方法,像vector一样使用[]访问任意元素,但是随机访问速度比不上vector快,因为它要内部处理堆跳转 deque也有保留空间.另外,由于deque不要求连续空间,所以可以保存的元素比vector更大,这点也要注意一下.还有就是在前面和后面添加元素时都不需要移动其它块的元素,所以性能也很高。

因此在实际使用时,如何选择这三个容器中哪一个,应根据你的需要而定,一般应遵循下面的原则:

1、如果你需要高效的随即存取,而不在乎插入和删除的效率,使用vector

2、如果你需要大量的插入和删除,而不关心随即存取,则应使用list

3、如果你需要随即存取,而且关心两端数据的插入和删除,则应使用deque。


4.stack栈模型

底层一般用list或deque实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时

▽ 基础数据类型的stack

int main(int argc, const char * argv[]) {        //定义stack对象    stack
s1; //入栈 s1.push(1); s1.push(2); s1.push(3); s1.push(4); //打印栈顶元素,并出栈 while (!s1.empty()) { //取出栈顶元素 cout << "当前栈顶元素" << s1.top() << endl; //获取栈的大小 cout << "当前栈的大小" << s1.size() << endl; //出栈 s1.pop(); } return 0;}复制代码

▽ 复杂数据类型的stack

//定义类class Teacher {
public: char name[32]; int age; void printT() { cout << "age = " << age << endl; } };int main(int argc, const char * argv[]) { Teacher t1, t2, t3; t1.age = 22; t2.age = 33; t3.age = 44; //定义栈容器 stack
s1; //入栈 s1.push(t1); s1.push(t2); s1.push(t3); //出栈并打印 while (!s1.empty()) { //打印栈顶元素 Teacher tmp = s1.top(); tmp.printT(); //出栈 s1.pop(); } return 0;}复制代码

5.queue队列模型

底层一般用list或deque实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时 (stack和queue其实是适配器,而不叫容器,因为是对容器的再封装)

#include 
void main(){ queue
q; q.push(1); q.push(2); q.push(3); cout << "对头元素" << q.front() <
q; q.push(t1); q.push(t2); q.push(t3); while (!q.empty()) { Teacher tmp = q.front(); tmp.printT(); q.pop(); }}复制代码

6.priotriy_queue优先级队列容器

底层数据结构一般为vector为底层容器,堆heap为处理规则来管理底层容器实现

优先级队列分为:最小值优先队列和最大值优先队列。

此处的最大值、最小值是指队头的元素(增序、降序)。默认,是创建最大值优先级队列。 定义优先级的方法:

priority_queue默认定义int类型的最大值队列

priority_queue<int, vector, less>定义int型的最大值优先队列

priority_queue<int, vector, greater>定义int型的最小值队列

上面的定义中,less和greater相当于谓词,是预定义好的排序函数,称之为“仿函数”。

void main(){    //定义优先级队列(默认是最大值优先级队列)    priority_queue
p1; //定义一个最大优先级队列 //less是提前定义好的预定义函数 相当于谓词 priority_queue
, less
> p2; //定义一个最小值优先级队列v priority_queue
, greater
> p3; //给默认的最大优先级队列入栈 p1.push(33); p1.push(11); p1.push(55); p1.push(22); //打印最大优先级的对头元素 cout<<"对头元素:"<< p1.top() <

7.set容器

集合, 用来判断某一个元素是不是在一个组里面,使用的比较少,底层数据结构为红黑树,有序,不重复

【set元素的插入和删除】

set提供了insert和erase函数,用来对元素进行插入和删除操作。

void main(){    set
set1; //插入元素 for (int i = 0; i<5; i++) { int tmp = rand(); set1.insert(tmp); } //重复插入元素(会插入不成功,下一节会分析如果根据返回值判断是否插入成功) set1.insert(100); set1.insert(100); set1.insert(100); set1.insert(100); for (set
::iterator it = set1.begin(); it != set1.end(); it++) { cout << *it <<" "; } //删除集合 while(!set1.empty()) { //获取头部 set
::iterator it = set1.begin(); //打印头部元素 cout << *it << endl; //从头部删除元素 set1.erase(set1.begin()); } }复制代码

【普通数据类型的排序】

set容器是有序的集合,默认的顺序是从小到大的。创建集合的方式:

上面的less和greater就是仿函数,集合会根据这个仿函数的返回值是否为真类进行排序。

//仿函数的原型,下面是C++提供的默认的greater的仿函数(删除了宏定义后的)struct greater{
bool operator()(const int &left, const int &right) const { //如果左值>右值,为真。从大到小的排列 return left > right; }};复制代码

添加进set集合的元素确实是有序的。

void main(){    //默认,从小到大    set
set1; //从小到大--默认就是 set
> set2; //从大到小 set
> set3; //添加元素 for (int i = 0; i < 5; i++) { int tmp = rand(); set3.insert(tmp); } //遍历 for (set
::iterator it = set3.begin(); it != set3.end(); it++) { cout<< *it << " "; }}复制代码

【自定义对象的排序】

基础数据类型的set是有序的关键原因是greater和less仿函数。

自定义对象的有序是通过自定义仿函数来实现。

仿函数,之所以叫仿函数,是因为它跟函数很像,但并不是一个函数。它的结果如下,只要我们实现了这个仿函数,我们也可以对自定义对象进行排序。

//定义仿函数的结构体struct FunctionName{
//重载了()运算符,实现两个自定义对象的比较 bool opeartor() (Type &left, Type &right) { //左值大于右值,从大到小的顺序 if(left > right) return true; else return false; }};复制代码

下面,我们自定义一个Student对象,根据年龄进行排序,将对象加入到set集合中,并进行打印。

//定义student对象class Student {
public: Student(const char *name, int age) { strcpy(this->name, name); this->age = age; } public: char name[64]; int age;};//提供仿函数,用于自定义对象的set进行排序,要写一个仿函数,用来排序struct FuncStudent{
//重载了括号操作符,用来比较大小 bool operator() (const Student &left, const Student &right) { //如果左边比右边小,从小到大按照年龄排序 if(left.age < right.age) return true; else return false; } };void main(){ Student s1("s1",32); Student s2("s2",22); Student s3("s3",44); Student s4("s4",11); Student s5("s5",22); //创建集合,采用从小到大的排序 set
set1; //插入数据 set1.insert(s1); set1.insert(s2); set1.insert(s3); set1.insert(s4); //插入不进去(年龄有重复的,所以插不进去了),要通过返回值来确保是否插入成功 set1.insert(s5); //遍历 for (set
::iterator it = set1.begin(); it != set1.end(); it++) { cout << it->age << "\t" << it->name <

【pair类型的返回值】

pair类型,就类似于Swift语言中的“元组”的概念,这个类型包含了多个数据类型,在函数返回的时候,可以同时返回多个值。

它实际上是一个结构体。它包含了两个属性,first和second。

template 
struct pair{
typedef _T1 first_type; typedef _T2 second_type; _T1 first; _T2 second;}复制代码

set集合中的元素是唯一的,重复的元素插入会失败。

判断是否插入成功,我们可以通过insert函数的返回值来判断,它的返回值是一个pair类型。

insert函数的原型: pair<iterator,bool> insert(const value_type& __v)

返回的是pair<iterator, bool>类型,pair的第一个属性表示当前插入的迭代器的位置,第二个属性表示插入是否成功的bool值。我们可以通过第二个属性来判断元素是否插入成功。

//pair的使用判断set的insert函数的返回值void test3(){    Student s1("s1",32);    Student s2("s2",22);    Student s3("s3",44);    Student s4("s4",11);    Student s5("s5",22);        //创建集合,采用从小到大的排序    set
set1; //插入数据,接收返回值 pair
::iterator, bool> pair1 = set1.insert(s1); if (pair1.second == true) { cout << "插入s1成功" <

【set查找元素】

set容器提供了多个函数用来查找元素

void test4(){    set
set1; for (int i = 0; i < 10; i++) { set1.insert(i+1); } //遍历 for (set
::iterator it = set1.begin(); it != set1.end(); it++) { cout << *it <
::iterator it0 = set1.find(5); cout << "it0:" << *it0 <
::iterator it1 = set1.lower_bound(5); cout << "it1:" << *it1 <
::iterator it2 = set1.upper_bound(5); cout << "it2:" << *it2 <
=5,另一个是>5 pair
::iterator, set
::iterator> mypair = set1.equal_range(5); set
::iterator it3 = mypair.first; set
::iterator it4 = mypair.second; cout << "it3:" << *it3 <

8.multiset容器

底层数据结构为红黑树,有序,可重复

multiset容器,与set容器相似,但是multiset容器中的元素可以重复。另外,他也是自动排序的,容器内部的值不能随便修改,因为有顺序的。

void test5(){    //定义multiset    multiset
set1; //从键盘不停的接收值 int tmp = 0; printf("请输入multiset集合的值:"); scanf("%d", &tmp); while (tmp != 0) { set1.insert(tmp); scanf("%d", &tmp); } //迭代器遍历 for (multiset
::iterator it = set1.begin(); it != set1.end(); it++) { cout<< *it <<" "; } cout <
::iterator it = set1.begin(); cout << *it << " "; set1.erase(it); }}复制代码

9.map容器

映射,相当于字典,把一个值映射成另一个值,如果想创建字典的话使用它。底层采用的是树型结构,多数使用平衡二叉树实现,查找某一值是常数时间,遍历起来效果也不错,只是每次插入值的时候,会重新构成底层的平衡二叉树,效率有一定影响。底层数据结构为红黑树,有序,不重复

【map元素的插入与删除】

int main(){    map
map1; //insert方法插入 //--1 通过pair
(1,”chenhua“) 构造pair元素 map1.insert(pair
(1,"chenhua")); //--2 通过make_pair构造pair元素 map1.insert(make_pair(2,"mengna")); //--3 通过value_type构造pair元素 map1.insert(map
::value_type(3,"chenmeng")); //[]直接插入 map1[4] = "menghua"; //重复插入(插入会不成功) pair
::iterator, bool> pair1 = map1.insert(make_pair(2, "haha")); if (pair1.second) { cout << "重复插入成功" << endl; }else{ cout << "重复插入失败" << endl; } //元素的修改 //map[1] = "22"的方式,如果不存在键则插入,存在键则修改 map1[2] = "haha"; //元素的删除 //--删除值为"haha"的元素 for (map
::iterator it = map1.begin(); it != map1.end(); it++) { if (it->second.compare("haha") == 0) { map1.erase(it); } } //遍历 for (map
::iterator it = map1.begin(); it != map1.end(); it++) { cout << it->first << "\t" << it->second << endl; } return 0;}复制代码

【map元素的查找】

map提供了两个函数进行key的查找:find和equal_range。

int main(){    //定义map    map
map1; map1[1] = "chenhua"; map1[2] = "mengna"; //查找key=100的键值对 map
::iterator it = map1.find(100); if (it != map1.end()) { cout << "存在key=100的键值对"; }else{ cout << "不存在" << endl; } //查找key = 1000的位置 //返回两个迭代器,第一个表示<=1000的迭代器位置,第二个是>1000的迭代器位置 pair
::iterator, map
::iterator> mypair = map1.equal_range(1000); if (mypair.first == map1.end()) { cout << "大于等于5的位置不存在" << endl; }else{ cout << mypair.first->first << "\t" << mypair.first->second << endl; } if (mypair.second == map1.end()) { cout << "大于5的位置不存在" << endl; }else{ cout << mypair.second->first << "\t" << mypair.second->second << endl; } return 0;}复制代码

10.multimap容器

底层数据结构为红黑树,有序,可重复

multimap容器,与map容器的唯一区别是:multimap支持多个键值。

由于支持多个键值,multimap提供了cout函数来计算同一个key的元素个数。

class Person {
public: string name; //姓名 int age; //年龄 string tel; //电话 double sal; //工资 };void test(){ Person p1,p2,p3,p4,p5; p1.name = "王1"; p1.age = 31; p2.name = "王2"; p2.age = 31; p3.name = "张3"; p3.age = 31; p4.name = "张4"; p4.age = 31; p5.name = "钱5"; p5.age = 31; multimap
map2; //sale部门 map2.insert(make_pair("sale", p1)); map2.insert(make_pair("sale", p2)); //development部门 map2.insert(make_pair("development", p3)); map2.insert(make_pair("development", p4)); //Finanncial部门 map2.insert(make_pair("Finanncial", p5)); //遍历 for (multimap
::iterator it = map2.begin(); it != map2.end(); it++) { cout << it->first << "\t" << it->second.name << endl; } //按部门显示员工信息 int developNum = (int) map2.count("development"); cout << "development部门人数:" << developNum << endl; multimap
::iterator it2 = map2.find("development"); int tag = 0; while (it2 != map2.end() && tag < developNum) { cout << it2->first << "\t" << it2->second.name <
::iterator it = map2.begin(); it != map2.end(); it++) { if (it->second.age == 32) { it->second.name = "32"; } }}int main(int argc, const char * argv[]) { test(); return 0;}复制代码

11.hash_set

底层数据结构为hash表,无序,不重复


12.hash_multiset

底层数据结构为hash表,无序,可重复


13.hash_map

底层数据结构为hash表,无序,不重复


14.hash_multimap

底层数据结构为hash表,无序,可重复

二、STL容器的通用性探究

STL的容器主要利用了C++的模板特性来实现。需要注意:

针对容器,容器之间也支持拷贝。所以需要注意:

【STL容器的元素拷贝】 如果容器元素如果没有实现拷贝构造函数,出现浅拷贝后的崩溃问题。

#include 
#include
#include
using namespace std;class Student {
public: Student(const char *name, int age) { cout << "构造函数" << endl; //分配内存空间 m_name = new char[strlen(name) + 1]; //值拷贝 strcpy(m_name, name); m_age = age; } ~Student() { printf("%p 指向的空间 调用析构函数\n", m_name); if (m_name != NULL) { delete []m_name; m_age = 0; } } private: char *m_name; int m_age; };int main(){ Student s1("chenhua",24); vector
v1; v1.push_back(s1); return 0;}复制代码

上面的代码段,运行后的结果如下:

构造函数0x100302a00 指向的空间 调用析构函数0x100302a00 指向的空间 调用析构函数复制代码

运行后,打印出结果后并报错。报错原因是同一个内存空间被释放了2次,导致的崩溃。

其根本原因是,v1将s1拷贝到容器,由于Student没有重写拷贝构造函数,从而出现了浅拷贝,只拷贝了地址。释放的时候毫无疑问出现错误。 如果我们给Student重写了拷贝构造函数和重载了等号操作符,则上面的错误就不会出现。

//重写拷贝构造函数Student(const Student &obj){    //分配内存空间    m_name = new char[strlen(obj.m_name) + 1];    //值拷贝    strcpy(m_name, obj.m_name);        m_age = obj.m_age;}    //重载等号运算符Student & operator=(const Student &obj){    //释放旧值    if (m_name != NULL) {        delete [] m_name;        m_age = 0;    }        //分配内存空间并赋值    m_name = new char[strlen(obj.m_name) + 1];    strcpy(m_name, obj.m_name);    m_age = obj.m_age;        return *this;}复制代码

三、STL容器的比较

内容参考:

转载于:https://juejin.im/post/5c9de926f265da30b53eb970

你可能感兴趣的文章
我是不是在浪费生命?
查看>>
XenApp_XenDesktop_7.6实战篇之十九:安装、升级和配置StoreFront 3.0
查看>>
redis 使用总结
查看>>
老罗的创业故事演讲
查看>>
经验之谈:破解网络竞价菜鸟迷茫困局
查看>>
好书分享:《SEO实战密码》第3版
查看>>
如何编写更好的SQL查询:终极指南-第二部分
查看>>
VMware vCenter Operations Manager安装与基本配置
查看>>
Shell脚本监控WEB服务是否正常
查看>>
了解并下载CentOS的网络渠道
查看>>
理解并配置:IPv6的静态路由与默认路由
查看>>
HTTP协议下客户/服务器模式中信息交换的实现
查看>>
【view桌面虚拟化系列】2-View搭建
查看>>
查看终端服务许可证使用情况
查看>>
体验vSphere 6之2-vCenter 6
查看>>
SQL Server 2012 AlwaysOn高可用配置之三:安装“故障转移群集”功能
查看>>
新京报:百度外卖直营店月入350万,使用过期菜品内幕曝光
查看>>
运维自动化之使用PHP+MYSQL+SHELL打造私有监控系统(三)
查看>>
【VMCloud云平台】SCOM进阶篇-全球监视器
查看>>
SQL语句常见优化十大案例
查看>>