变长模板

c语言支持函数变参,通过va_list, va_start, va_arg, va_end系列函数获取参数,但是函数并不知道到参数的具体类型,va_arg获取参数的原理是按照类型去通过指针去参数列表取得的,只适合用于POD类型

c++实现了变参模板,即同时传递变量和类型;模板参数包和函数参数包可以将多个参数打包看作一个参数,然后在模板推导时通过包扩展将其解包。

1
2
template<typename... Args>
class Template : privateB<A...>

如何才能利用模板参数包及包扩展,使得模板能够接受任意多 的模板参数,且均能实例化出有效的对象呢?

通过递归的方法,参套包含,并且指定边界条件

1
2
3
template<typename... T> class tuple;
template<typename Head, typename... Tail> class tuple<Head, Tail...> : private tuple<Tail...> { Head head; };
template<>class tuple<> {};

智能指针

智能管理堆内存的指针,能够在析构时自动释放内存

unique_ptr:

share_ptr:共享对象所有权的智能指针,通过过share_count计数实现拷贝,当析构时计数为0才真正删除所指内存

weak_ptr:share_ptr的弱引用,使用时必须转换为share_ptr,解决环状引用

环状引用:当a析构时A的计数为1,b析构时B的计数为1,造成内存泄漏

1
2
3
4
5
6
7
8
9
10
11
12
13
class B;
class A{
public:
shared_ptr<B> pb;
};
class B{
public:
shared_ptr<A> pa;
}
shared_ptr<A> a(new A);
shared_ptr<B> b(new B);
a->pb = b;
b->pa = a;

share_ptr和weak_ptr实现原理:shared_ptr封装了原生指针和一个计数块cblock,可以看到share_ptr通过shared_count计数,并且析构后如果还有weak_ptr在观察,则不会释放cblock;而weak_ptr想要使用必须通过lock转换share_ptr并且在data_指针存在时才能转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
struct cblock {
int shared_count = 1;
int weak_count = 0;
};
template<class T>
class shared_ptr
{
...
shared_ptr(const shared_ptr& sp) noexcept
...
if (cblock_) ++cblock_->shared_count;
...
~shared_ptr() {
dec_shared_count();
}
private:
void dec_shared_count() noexcept {
if (cblock_) {
if (--cblock_->shared_count <= 0) {
delete data_;
data_ = nullptr;
if (cblock_->weak_count <= 0) {
delete cblock_;
cblock_ = nullptr;
}
}
}
}
T* data_ = nullptr;
cblock* cblock_ = nullptr;
};

视图

string_view

c++17引入新目标,在处理大型字符串时避免不必要的复制

view一词说明其不包含字符串的管理权,相当引用,string则拥有内存

主要用于访问和比较字符串内容

span

指向数据的视图,无管理权限

1
2
3
std::vector<int> vec{1,2,3,4,5};
std::span<int> span(vec.begin(),vec.end());
auto& sub_span = span..subspan(1,3);

c++20协程

C++ 协程会在开始执行时的第一步就使用 operator new 来开辟一块内存来存放这些信息,这块内存或者说这个对象又被称为协程的状态(coroutine state)

如果参数是值类型,他们的值或被移动或被复制(取决于类型自身的复制构造和移动构造的定义)到协程的状态当中;如果是引用、指针类型,那么存入协程的状态的值将会是引用或指针本身,而不是其指向的对象,这时候需要开发者自行保证协程在挂起后续恢复执行时参数引用或者指针指向的对象仍然存活。

co_await