C++stl 2

三十四章 内存和资源

  1. 拟容器

    1. T[N]
    2. array<T, N>
    3. bitset
    4. vector
    5. pair<T,U>
    6. tuple
    7. basic_string
    8. valarray
  2. array: 固定大小的给定类型的元素序列,元素数目在编译时指定

    1. 理解array的最好方式是将其视为固定大小的内置数组,但不会隐式的,出乎意料的转换为指针类型,且提供了了一些便利函数,array并不是元素句柄,而是直接包含元素:

      template<typename T, size_t N>

      struct array{

      ​ void fill(const T& v);

      ​ void swap(array&)noexcept(noexcept(swap(declval<T&>(), declval<T&>())));//如果T的swap抛出异常,则array<T,N>的swap也会抛出异常

      ​ T ___elem[N]; //实现细节

      }

    2. array没有构造函数或分配器

    3. 可以将array看作一个所有元素类型都相同的tuple,标准库提供了这一视角的支持

  3. bitset: 包含N个二进制位的数组,提供了一种位引用(代理)类型,位位置从右到左编号

  4. 构造函数:bitset可以用指定个0构造,也可以用一个unsigned long long int中的二进制位或一个string构造:
    1. bitset bs{} // N个二进制0
    2. bitset bs{n}. //用n中二进制初始化,n是一个unsigned long long int
    3. bitset bs{s,i,n,z,o} //用s中区间[i, i+n)内的n个二进制位初始化,s是一个basic_string<C,Tr,A>;z是表示0的字符,类型C,o是表示1的字符,类型C;
    4. bitset bs{s,i,n,z} // bitset bs{s,i,n,z,C{‘1’}}
    5. bitset bs{s,i,n}. // bitset bs{s,i,n,C{‘0’}, C{‘1’}}
    6. bitset bs{s,i}. // bitset bs{s,i,npos,C{‘0’},C{‘1’}}
    7. bitset bs{s}. // bitset bs{s,0,npos,C{‘0’},C{‘1’}}
    8. bitset bs{p,n,z,o} //用序列[p,p+n)中的n个二进制位初始化,p是一个类型为C*的C风格字符串,z是表示0的字符,o是表示1的字符
    9. bitset bs{p,n,z} // bitset bs{p,n,z,C{‘1’}}
    10. bitset bs{p,n}. // bitset bs{p,n,C{‘0’}, C{‘1’}}
    11. bitset bs{p}. //. bitset bs{p,npos, C{‘0’}, C{‘1’}}
  5. 操作单独的二进制位和整体的位集合
    1. bs[i]
    2. bs.test(i)
    3. bs&=bs2
    4. bs =bs2
    5. bs^=bs2
    6. bs«=n. //填充0
    7. bs»=n//填充0
    8. bs.set() //所有位置1
    9. bs.set(i, v) //bs[i] = v
    10. bs.reset() //所有位置0
    11. bs.reset(i)
    12. bs.flip() //反转每一位
    13. bs.flip(i)
    14. bs2=~bs
    15. bs2=bs«n
    16. bs2=bs»n
    17. bs3 = bs & bs2
    18. bs3 = bs bs2
    19. bs3 = bs ^ bs2
    20. is » bs
    21. os « bs
  6. 更多操作
    1. n=bs.to_ulong()
    2. n=bs.to_ullong()
    3. s=bs.to_string<C,Tr,A>(c0, c1) //s[i] = b[i]?c1:c0;
    4. s=bs.to_string<C,Tr,A>(c0) //s=template to_string<C,Tr,A>(c0, C{‘1’})
    5. s=bs.to_string<C,Tr,A>() // s=template to_string<C,Tr,A>(C{‘0’}, C{‘1’})
    6. n=bs.count() //1的个数
    7. n=bs.size() //二进制的位数
    8. bs == bs2
    9. bs != bs2
    10. bs.all(). //全为1?
    11. ba.any() // 有1?
    12. bs.none() // 没有1?
    13. hash<bitset< N»
  7. vector: 具有分配器,也能改变大小,索引最大的元素保存在高地址,与bitset的内存布局相反

  8. pair

    1. pair p{piecewise_construct,t,t2} 用tuple t的元素构造p.first, 用tuple t2的元素构造p.second
    2. p=make_pair(x,y)
    3. tuple_size::value 类型T的pair的大小
    4. tuple_element<N,T>::type 若N==0,得到first的类型,若N==1,得到second的类型
    5. get(p) 指向pair p的第N个元素的引用;N必须是0或1
  9. tuple

    1. tuple的类型与=的运算对象及swap()的实参的类型不必一致,当且仅当对元素的隐式操作有效,一个tuple操作才有效。例如:

      tuple<string, vector, int> t2 = make_tuple("hello, world", vector{1,2,3}, 'x');

      一对运算对象(或实参)的元素数目必须相等。

      通用tuple的构造函数是explicit

    2. 辅助函数

      1. t=make_tuple(args)
      2. t=forward_as_tuple(args) //tuple t包含指向args元素的右值引用,可以利用t转发args中的元素
      3. t=tie(args) //t是一个tuple,包含指向args中元素的左值引用,因此可以利用t向args中的元素赋值
      4. t=tuple_cat(args) //连接tuple,args是一个或多个tuple,args中tuple的成员按序保存在t中
      5. tuple_size::size // tuple的元素数
      6. tuple_element<N,T>::type //第N个元素的类型
      7. get(t) //第N个元素的引用
      8. use_allocator<T,A>::value // 一个tuple可以用一个类型为A的分配器分配吗?
    3. 例子

      auto t = make_tuple(2.7, 299, “Han”);

      double c

      string name;

      tie(c, ignore, name) =t;// c=2.7, name=”Han”,

      对象ignore的类型会忽略赋值

  10. unique_ptr<T, D>

    1. 不能拷贝,但可以移动

    2. 可带有关联的释放器deleter, 默认为delete

    3. bool b{up} //转换为bool值,up.cp != nullptr, cp是包含指针

    4. x=*up,//包含的对象不是数组,x=up.cp

    5. x=up->m, //只适用包含的对象不是数组的情况, x=up.cp->m

    6. x=up[n], //只适用包含的对象是数组, x=up.cp[n]

    7. x=up.get() // x=up.cp

    8. up.get_deleter()

    9. p=up.release() //p=up.cp, up.cp=nullptr

    10. up.reset(p)

    11. up.reset()

    12. up.swap(up2)

    13. swap(up, up2)

    14. ==, !=, <, <=, >, >=

    15. 为避免切片,Derived[]不能作为unique_ptr<Base[]>的实参:

      unique_ptr< Shape> ps{new Circle{p, 20}}//正确

      unique_ptr< Shape[]> pa{new Cirle[]{Circle{p,20}, Circle{p2,40}}}//错误

  11. shared_ptr

    1. 默认释放器delete。shared_ptr 有缺点:
    2. shared_ptr的循环链表会导致资源泄漏,使用weak_ptr打破
    3. 比起限定作用域的对象,共享所有权的对象活跃时间更长
    4. 多线程环境下,共享指针代价很高(使用计数的数据竞争)
    5. 析构函数执行时间不可预测
    6. 优先选择unique_ptr
    7. sp.reset()
    8. sp.reset(p)
    9. sp.reset(p,d)
    10. sp.reset(p,d,a)
    11. n=sp.use_count() //返回引用计数的值
    12. sp.unique() //uc==1?
    13. x=sp.owner_before(pp)//x是一个序函数(严格弱序),pp是一个shared_ptr或weak_ptr
    14. sp.swap(sp2)
    15. sp=make_shared(args)//用args实参构造类型为T的对象,使用new分配内存
    16. sp=allocate_shared(a, args) //同15, 使用a分配内存
    17. ==,!=, <,<=,>,>=, swap(sp, sp2)
    18. sp2=static_pointer_cast(sp)//sp2=shared_ptr(static_cast<T*>(sp.cp))
    19. sp2=dynamic_pointer_cast(sp)//sp2=shared_ptr(dynamic_cast<T*>(sp.cp))
    20. sp2=const_pointer_cast(sp)//sp2=shared_ptr(const_cast<T*>(sp.cp))
    21. dp=get_deleter(sp)
    22. os«sp
  12. weak_ptr指向一个shared_ptr管理的对象,为了访问对象,可使用成员函数lock将weak_ptr转化为shared_ptr

    1. 弱使用计数(wuc)用来保持使用计数结构活跃,该结构包含”使用计数”,”释放器”,”弱使用计数”;
    2. Weak_ptr wp{pp} //cp=pp.cp, ++wuc, pp是一个weak_ptr或shared_ptr
    3. wp.~weak_ptr() //对*cp无影响,–wuc
    4. n=wp.use_count() // n是指向*cp的shared_ptr的数目
    5. wp.expired() // 还有指向*cp的shared_ptr吗?
    6. sp=wp.lock()//创建一个指向*cp的shared_ptr
  13. 分配器 待续

三十五章 工具