智能指针
智能管理堆内存的指针,能够在析构时自动释放内存
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