关联容器
1、关联容器的迭代器是双向迭代器。
2、有序关联容器的关键字类型:
- 关键字类型必须定义一个严格弱序
- multiset必须提供两个类型:关键字类型以及比较操作符
3、pair类型:make_pair(v1,v2),返回一个用v1和v2初始化的pair。
///程序8
pair<string,int> preocess(vector<string> &v){
if(!v.empty())
return {v.back(),v.back().size()};//列表初始化
else
return pair<string,int>();//隐式构造返回值
}
4、关联容器操作
- key_type(此类容器类型的关键字类型)、mapped_type(每个关键字关联的类型(map))、以及value_type(对于set与key_type相同
,对于map为:pair < const key_type,mapped_type >) - 对于map的value_type类型,不能改变其关键字成员的值,因为是const类型。
5、添加元素。insert(emplace)方法:会返回一个pair类型,fisrt是一个迭代器,指向具体给定关键字的元素;sencod为bool类型,插入是否成功
//map的几种插入方式:
word_map.insert({word,1});
word_map.insert(make_pair(word,1));
word_map.insert(pair<string,int>(word,1));
word_map.insert(map<string,int>::value_type(word,1));
6、元素访问(find,count,lower_bound,upper_bound,equal_range)
lower_bound,upper_bound:前:返回一个迭代器,指向第一个关键字不小于k的元素;后:指向第一个关键字大于k的元素
equal_range:返回一个迭代器pair,表示关键字等于k的元素范围。若k不存在,pair的两个成员均等于end();
动态内存
1、shared_ptr与unique_ptr,在头文件memory中
- 都支持的一些操作
shared_ptr<T> sp;
unique_ptr<T> up;//空智能指针,指向类型为T的对象
p;//若P指向一个对象,则为true
*P;
p->mem <==> (*p).mem;
p.get();//返回p中保存的指针
- shared_ptr独有的操作
make_shared<T>(args);//使用args初始化一个指向T对象的shard_ptr
shared_ptr<T> p(q);//p为q的拷贝,增加q中的引用计数
p = q;//在p和q都是shared_ptr的情况下,p的引用计数会减少,q的引用计数会增加
- 定义和改变shared_ptr的其他方法
shared_ptr<T> p(q);//q必须指向new分配的内存
shared_ptr<T> p(u);//接管u(unique_ptr)的所有权,将u置空
shared_ptr<T> p(q,d);//p接管q的所有权,并且可调用d来代替delete
/*
void end_connect(connection *p){disconnect(*p);}
connection c = connect(&d);
shared_ptr<connection> p(&c,end_connect);
*/
q.reset();//若q是唯一指向对象shared_ptr,释放此对象
q.reset(p);//令q指向p
q.reset(p,d);
- unique_ptr的操作
unique_ptr<T> u;
unique_ptr<T,D> u;//指定类型为D的对象代替delete(P419有具体例子)
u = nullptr;//释放u,并置空
u.release();//释放u,并返回u所指向的指针
u.reset();
u.reset(p);//若存在p,则u指向p;否则置空
///程序1
void test_uniqueptr(){
unique_ptr<string> p1(new string("TEST"));
unique_ptr<string> p2(p1.release());//转移所有权,并置空p1;
//p2.release();//error,p2不会释放,而且丢失了指针
auto p = p1.release();//ok,记得delete(p)
}
- shared_ptr和new结合使用
①接受指针参数的智能指针的构造函数是explicit的,因此不能将一个内置的指针转换为智能指针,必须使用显示初始化形式
shared_ptr<int> p1 = new int(1024);//error
shared_ptr<int> p2(new int(1024));//ok
//返回
shared_ptr<int> clone(int p){
//return new int(p);//error 不能隐式转换一个普通的指针
return shared_ptr<int>(new int(p));
}
②不能混用普通指针和智能指针
//程序2
//在调用process时,ptr创建并被初始化
void process(shared_ptr<int> ptr){
//使用ptr
}//ptr离开作用域,被销毁
void test_smart_ptr(){
shared_ptr<int> p(new int(42));//引用计数为1
process(p);//拷贝,在process中引用计数为2
int i = *p;//ok,引用计数为1
}
void test_com_ptr(){
int *x(new int(42));
process(x);//不能将int *传递给shared_ptr
process(shared_ptr<int> (x));//临时的shared_ptr,参数传递完后,引用计数会减少
int i = *x;//未定义
}
- 传递unique_ptr参数和返回unique_ptr:由于uniq_ptr拥有它指向对象,因此unique_ptr不支持拷贝和赋值操作;但是可以拷贝或者赋值一个将要被销毁的uniq_ptr
unique_ptr<int> clone(int p){
return unique_ptr<int> (new int(p));//ok
}
unique_ptr<int> clone(int p){
unique_ptr<int> ret(new int(p));
return ret;//ok
}
2、动态数组
- 不能对动态数组调用begin和end,因为分配的内存不是一个数组类型
- shared_ptr、unique_ptr与动态数组(注意区别)
unique_ptr<int []> up(new int[10]);
up.release();//自动调用delete[]
for(size_t i = 0; i != 10; i++)
up[i] = i;//unique_ptr访问数组
//使用shared_ptr
shared_ptr<int> sp(new int[10],[](int *p){delete[] p;});
sp.reset();//使用提供的lambda释放数组
for(size_t i = 0; i != 10; i++)
*(sp.get()+i) = i;
- allocator,可以将内存分配与对象构造分离开来
3、使用与管理动态内存
- 使用动态内存的需求:
-未知使用对象个数
-未知使用对象的准确类型
-需要在多个对象之间共享数据 - 管理需要注意
- 不要忘记delete内存,易导致内存泄漏
- 不要使用已经释放内存的对象,注意使用之前作check
- 不要对同一块内存释放两次
4、文本查询程序
///程序3
//头文件TextQuery.h
#ifndef TEXTQUERY_H
#define TEXTQUERY_H
#include <vector>
#include <map>
#include <set>
#include <string>
#include <fstream>
#include <memory>
#include <iostream>
using namespace std;
using line_no = vector<string>::size_type;
//前向声明(不完全类型),可以定义其指针、引用、或者作为函数的参数或返回值
class QueryResult;
class TextQuery
{
public:
TextQuery(ifstream &);
QueryResult query(const string &) const;
private:
shared_ptr<vector<string>> file;//输入文件
map<string,shared_ptr<set<line_no>>> wm;//每个单词与对应行号的集合
};
class QueryResult
{
friend ostream & print(ostream &,const QueryResult &);
public:
QueryResult(string s,
shared_ptr<set<line_no>> p,
shared_ptr<vector<string>> f):
sought(s),lines(p),file(f){}
private:
string sought;
shared_ptr<set<line_no>> lines;
shared_ptr<vector<string>> file; //将与TextQuery共用一个file,智能指针引用计数机制
};
#endif // TEXTQUERY_H
//TextQuery.cpp
#include "TextQuery.h"
#include <sstream>
TextQuery::TextQuery(ifstream &is):file(new vector<string>)
{
string text;
while (getline(is,text)) { //读取每行数据
file->push_back(text); //保存当前行
int num = file->size() - 1; //行号
istringstream line(text); //分割每个单词
string word;
while (line >> word) {
auto &lines = wm[word]; //lines为shared_ptr类型
if(!lines)
lines.reset(new set<line_no>);
lines->insert(num);
}
}
}
QueryResult TextQuery::query(const string &sought) const
{
static shared_ptr<set<line_no>> nodata(new set<line_no>);
auto loc = wm.find(sought);
if(loc == wm.end())
return QueryResult(sought,nodata,file);
else
return QueryResult(sought,loc->second,file);
}
ostream &print(ostream &os, const QueryResult &qr)
{
os << qr.sought << "occurs" << qr.lines->size() << " times" << endl;
for(auto num: *qr.lines)
os << "\t(line "<< num+ 1 <<")" << *(qr.file->begin() + num) << endl;
return os;
}