三十四章 内存和资源
-
拟容器
- T[N]
- array<T, N>
- bitset
- vector
- pair<T,U>
- tuple
- basic_string
- valarray
-
array: 固定大小的给定类型的元素序列,元素数目在编译时指定
-
理解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]; //实现细节
}
-
array没有构造函数或分配器
-
可以将array看作一个所有元素类型都相同的tuple,标准库提供了这一视角的支持
-
-
bitset
: 包含N个二进制位的数组,提供了一种位引用(代理)类型,位位置从右到左编号 - 构造函数:bitset可以用指定个0构造,也可以用一个unsigned long long int中的二进制位或一个string构造:
- bitset bs{} // N个二进制0
- bitset bs{n}. //用n中二进制初始化,n是一个unsigned long long int
- bitset bs{s,i,n,z,o} //用s中区间[i, i+n)内的n个二进制位初始化,s是一个basic_string<C,Tr,A>;z是表示0的字符,类型C,o是表示1的字符,类型C;
- bitset bs{s,i,n,z} // bitset bs{s,i,n,z,C{‘1’}}
- bitset bs{s,i,n}. // bitset bs{s,i,n,C{‘0’}, C{‘1’}}
- bitset bs{s,i}. // bitset bs{s,i,npos,C{‘0’},C{‘1’}}
- bitset bs{s}. // bitset bs{s,0,npos,C{‘0’},C{‘1’}}
- bitset bs{p,n,z,o} //用序列[p,p+n)中的n个二进制位初始化,p是一个类型为C*的C风格字符串,z是表示0的字符,o是表示1的字符
- bitset bs{p,n,z} // bitset bs{p,n,z,C{‘1’}}
- bitset bs{p,n}. // bitset bs{p,n,C{‘0’}, C{‘1’}}
- bitset bs{p}. //. bitset bs{p,npos, C{‘0’}, C{‘1’}}
- 操作单独的二进制位和整体的位集合
- bs[i]
- bs.test(i)
- bs&=bs2
-
bs =bs2 - bs^=bs2
- bs«=n. //填充0
- bs»=n//填充0
- bs.set() //所有位置1
- bs.set(i, v) //bs[i] = v
- bs.reset() //所有位置0
- bs.reset(i)
- bs.flip() //反转每一位
- bs.flip(i)
- bs2=~bs
- bs2=bs«n
- bs2=bs»n
- bs3 = bs & bs2
-
bs3 = bs bs2 - bs3 = bs ^ bs2
- is » bs
- os « bs
- 更多操作
- n=bs.to_ulong()
- n=bs.to_ullong()
- s=bs.to_string<C,Tr,A>(c0, c1) //s[i] = b[i]?c1:c0;
- s=bs.to_string<C,Tr,A>(c0) //s=template to_string<C,Tr,A>(c0, C{‘1’})
- s=bs.to_string<C,Tr,A>() // s=template to_string<C,Tr,A>(C{‘0’}, C{‘1’})
- n=bs.count() //1的个数
- n=bs.size() //二进制的位数
- bs == bs2
- bs != bs2
- bs.all(). //全为1?
- ba.any() // 有1?
- bs.none() // 没有1?
- hash<bitset< N»
-
vector
: 具有分配器,也能改变大小,索引最大的元素保存在高地址,与bitset的内存布局相反 -
pair
- pair p{piecewise_construct,t,t2} 用tuple t的元素构造p.first, 用tuple t2的元素构造p.second
- p=make_pair(x,y)
- tuple_size
::value 类型T的pair的大小 - tuple_element<N,T>::type 若N==0,得到first的类型,若N==1,得到second的类型
- get
(p) 指向pair p的第N个元素的引用;N必须是0或1
-
tuple
-
tuple的类型与=的运算对象及swap()的实参的类型不必一致,当且仅当对元素的隐式操作有效,一个tuple操作才有效。例如:
tuple<string, vector
, int> t2 = make_tuple("hello, world", vector {1,2,3}, 'x'); 一对运算对象(或实参)的元素数目必须相等。
通用tuple的构造函数是explicit
-
辅助函数
- t=make_tuple(args)
- t=forward_as_tuple(args) //tuple t包含指向args元素的右值引用,可以利用t转发args中的元素
- t=tie(args) //t是一个tuple,包含指向args中元素的左值引用,因此可以利用t向args中的元素赋值
- t=tuple_cat(args) //连接tuple,args是一个或多个tuple,args中tuple的成员按序保存在t中
- tuple_size
::size // tuple 的元素数 - tuple_element<N,T>::type //第N个元素的类型
- get
(t) //第N个元素的引用 - use_allocator<T,A>::value // 一个tuple
可以用一个类型为A的分配器分配吗?
-
例子
auto t = make_tuple(2.7, 299, “Han”);
double c
string name;
tie(c, ignore, name) =t;// c=2.7, name=”Han”,
对象ignore的类型会忽略赋值
-
-
unique_ptr<T, D>
-
不能拷贝,但可以移动
-
可带有关联的释放器deleter, 默认为delete
-
bool b{up} //转换为bool值,up.cp != nullptr, cp是包含指针
-
x=*up,//包含的对象不是数组,x=up.cp
-
x=up->m, //只适用包含的对象不是数组的情况, x=up.cp->m
-
x=up[n], //只适用包含的对象是数组, x=up.cp[n]
-
x=up.get() // x=up.cp
-
up.get_deleter()
-
p=up.release() //p=up.cp, up.cp=nullptr
-
up.reset(p)
-
up.reset()
-
up.swap(up2)
-
swap(up, up2)
-
==, !=, <, <=, >, >=
-
为避免切片,Derived[]不能作为unique_ptr<Base[]>的实参:
unique_ptr< Shape> ps{new Circle{p, 20}}//正确
unique_ptr< Shape[]> pa{new Cirle[]{Circle{p,20}, Circle{p2,40}}}//错误
-
-
shared_ptr
- 默认释放器delete。shared_ptr 有缺点:
- shared_ptr的循环链表会导致资源泄漏,使用weak_ptr打破
- 比起限定作用域的对象,共享所有权的对象活跃时间更长
- 多线程环境下,共享指针代价很高(使用计数的数据竞争)
- 析构函数执行时间不可预测
- 优先选择unique_ptr
- sp.reset()
- sp.reset(p)
- sp.reset(p,d)
- sp.reset(p,d,a)
- n=sp.use_count() //返回引用计数的值
- sp.unique() //uc==1?
- x=sp.owner_before(pp)//x是一个序函数(严格弱序),pp是一个shared_ptr或weak_ptr
- sp.swap(sp2)
- sp=make_shared
(args)//用args实参构造类型为T的对象,使用new分配内存 - sp=allocate_shared(a, args) //同15, 使用a分配内存
- ==,!=, <,<=,>,>=, swap(sp, sp2)
- sp2=static_pointer_cast(sp)//sp2=shared_ptr
(static_cast<T*>(sp.cp)) - sp2=dynamic_pointer_cast(sp)//sp2=shared_ptr
(dynamic_cast<T*>(sp.cp)) - sp2=const_pointer_cast(sp)//sp2=shared_ptr
(const_cast<T*>(sp.cp)) - dp=get_deleter
(sp) - os«sp
-
weak_ptr指向一个shared_ptr管理的对象,为了访问对象,可使用成员函数lock将weak_ptr转化为shared_ptr
- 弱使用计数(wuc)用来保持使用计数结构活跃,该结构包含”使用计数”,”释放器”,”弱使用计数”;
- Weak_ptr wp{pp} //cp=pp.cp, ++wuc, pp是一个weak_ptr或shared_ptr
- wp.~weak_ptr() //对*cp无影响,–wuc
- n=wp.use_count() // n是指向*cp的shared_ptr的数目
- wp.expired() // 还有指向*cp的shared_ptr吗?
- sp=wp.lock()//创建一个指向*cp的shared_ptr
-
分配器 待续