C++学习整理(关联容器与动态内存)

关联容器

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 sp;
  unique_ptr up;//空智能指针,指向类型为T的对象
  p;//若P指向一个对象,则为true
  *P;
  p->mem <==> (*p).mem;
  p.get();//返回p中保存的指针
  • shared_ptr独有的操作
  make_shared(args);//使用args初始化一个指向T对象的shard_ptr
  shared_ptr p(q);//p为q的拷贝,增加q中的引用计数
  p = q;//在p和q都是shared_ptr的情况下,p的引用计数会减少,q的引用计数会增加
  • 定义和改变shared_ptr的其他方法
  shared_ptr p(q);//q必须指向new分配的内存
  shared_ptr p(u);//接管u(unique_ptr)的所有权,将u置空
  shared_ptr p(q,d);//p接管q的所有权,并且可调用d来代替delete
  /*
  void end_connect(connection *p){disconnect(*p);}
  connection c = connect(&d);
  shared_ptr p(&c,end_connect);
  */
  q.reset();//若q是唯一指向对象shared_ptr,释放此对象
  q.reset(p);//令q指向p
  q.reset(p,d);
  • unique_ptr的操作
  unique_ptr u;
  unique_ptr 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 
#include 
#include 
#include 
#include 
#include 
#include 
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>> wm;//每个单词与对应行号的集合
};

class QueryResult
{
friend ostream & print(ostream &,const QueryResult &);
public:
    QueryResult(string s,
                shared_ptr<set> p,
                shared_ptr<vector<string>> f):
        sought(s),lines(p),file(f){}
private:
    string sought;
    shared_ptr<set> lines;
    shared_ptr<vector<string>> file;    //将与TextQuery共用一个file,智能指针引用计数机制
};

#endif // TEXTQUERY_H

//TextQuery.cpp
#include "TextQuery.h"
#include 

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);
            lines->insert(num);
        }
    }
}

QueryResult TextQuery::query(const string &sought) const
{
    static shared_ptr<set> nodata(new set);
    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;
}

你可能感兴趣的:(学习,c++-primer)