智能指针

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

unique_ptr:独享对象所有权的智能指针,禁用拷贝构造和赋值函数,但可以通过右值引用进行拷贝,原来的对象指针变为nullptr

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简单实现:可以看到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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
struct cblock {
int shared_count = 1;
int weak_count = 0;
};

template<class T> class weak_ptr;

template<class T>
class shared_ptr
{
public:
shared_ptr() noexcept = default;

explicit shared_ptr(T* data)
: data_(data)
{
if (data_) {
cblock_ = new cblock();
}
}

shared_ptr(const shared_ptr& sp) noexcept
: data_(sp.data_)
, cblock_(sp.cblock_)
{
if (cblock_) {
++cblock_->shared_count;
}
}
template<class D>
shared_ptr(const shared_ptr<D>& sp) noexcept
: data_(sp.data_)
, cblock_(sp.cblock_)
{
if (cblock_) {
++cblock_->shared_count;
}
}

explicit shared_ptr(const weak_ptr<T>& wp) noexcept
: data_(wp.data_)
, cblock_(wp.cblock_)
{
if (cblock_) {
++cblock_->shared_count;
}
}
shared_ptr(shared_ptr&& sp) noexcept {
swap(sp);
sp.reset();
}
~shared_ptr() {
dec_shared_count();
}

shared_ptr& operator=(const shared_ptr& sp) noexcept {
shared_ptr tmp(sp);
swap(tmp);
return *this;
}
shared_ptr& operator=(shared_ptr&& sp) noexcept {
swap(sp);
sp.reset();
return *this;
}

T* get() const noexcept {
return data_;
}
T* operator->() const noexcept {
return data_;
}
T& operator*() const noexcept {
assert(*this);
return *data_;
}
explicit operator bool() const noexcept {
return data_!= nullptr;
}
void reset() noexcept {
dec_shared_count();
data_ = nullptr;
cblock_ = nullptr;
}
void reset(T* data) noexcept {
dec_shared_count();

cblock_ = new cblock();

}

private:
void swap(shared_ptr& sp) noexcept {
std::swap(data_, sp.data_);
std::swap(cblock_, sp.cblock_);
}
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;

template<class Y> friend class weak_ptr;
template<class Y> friend class shared_ptr;
};

template <class T>
class weak_ptr
{
public:
weak_ptr() noexcept = default;
weak_ptr(const weak_ptr& wp) noexcept
: data_(wp.data_)
, cblock_(wp.cblock_) {
if (cblock_) {
++cblock_->weak_count;
}
}
template <class D>
weak_ptr(const weak_ptr<D>& wp) noexcept
: data_(wp.data_)
, cblock_(wp.cblock_) {
if (cblock_) {
++cblock_->weak_count;
}
}

weak_ptr(const shared_ptr<T>& sp) noexcept
: data_(sp.data_)
, cblock_(sp.cblock_) {
if (cblock_) {
++cblock_->weak_count;
}
}
weak_ptr(weak_ptr&& wp) noexcept {
swap(wp);
wp.reset();
}
~weak_ptr() {
dec_shared_count();
}
weak_ptr& operator=(const weak_ptr& wp) noexcept {
weak_ptr tmp(wp);
swap(tmp);
return *this;
}
weak_ptr& operator=(weak_ptr&& wp) noexcept {
swap(wp);
wp.reset();
return *this;
}

void reset() noexcept {
dec_shared_count();
data_ = nullptr;
cblock_ = nullptr;
}

shared_ptr<T> lock() const noexcept {
return expired() ? nullptr : shared_ptr<T>(*this);
}

bool expired() const noexcept {
return cblock_ == nullptr || cblock_->shared_count <= 0;
}

private:
void swap(weak_ptr& wp) noexcept {
std::swap(data_, wp.data_);
std::swap(cblock_, wp.cblock_);
}
void dec_weak_count() noexcept {
if (cblock_) {
--cblock_->weak_count;
if(cblock_->weak_count <= 0 && cblock_->shared_count <= 0) {
delete cblock_;
cblock_ = nullptr;
}
}
}

T* data_;
cblock* cblock_;

template <class D> friend class shared_ptr;
};

视图

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