网站建设策划书格式及范文,静态做网站,莱芜吧贴吧最新消息,中国嘉兴门户网站一#xff1a;背景 我们知道 C 是手工管理内存的分配和释放#xff0c;对应的操作符就是 new/delete 和 new[] / delete[], 这给了程序员极大的自由度也给了我们极高的门槛#xff0c;弄不好就得内存泄露#xff0c;比如下面的代码#xff1a;void test() {int* i new i… 一背景 我们知道 C 是手工管理内存的分配和释放对应的操作符就是 new/delete 和 new[] / delete[], 这给了程序员极大的自由度也给了我们极高的门槛弄不好就得内存泄露比如下面的代码void test() {int* i new int(10);*i 10;
}int main() {test();
}这段代码因为用了 new 而忘了 delete导致在 nt heap 上分配的 i 随着栈地址的回收而成了一块孤悬海外的内存占用所以修正后的代码如下void test() {int* i new int(10);*i 10;delete i;
}int main() {test();
}但这种写法比较麻烦智者千虑必有一失总会有忘记加 delete 的时候那怎么办呢大家应该知道内存自动管理有两种手段。引用计数代表作有 PythonPHP还有 windows 的句柄管理。引用跟踪代表作有 C#JAVA 等一众工程化语言。因为 引用计数 实现比较简单主要就是记录下对象的引用次数次数为 0 则释放所以可完全借助 类的构造函数析构函数 和 栈的自动回收特性 弄一个简单的 引用计数 对应着如下四个关键词。auto_ptrshared_ptrunique_ptrweak_ptr接下来我们逐个聊一聊。二关键词解析 1. auto_ptr这是 C 最早出现一个的 简单引用计数法参考代码如下void test() {auto_ptrint ptr auto_ptrint(new int(10));
}int main() {test();
}接下来看下汇编代码auto_ptrint ptr auto_ptrint(new int(10));
...
00771D26 call std::auto_ptrint::auto_ptrint (07710FAh)
00771D2B lea ecx,[ebp-0D8h]
00771D31 call std::auto_ptrint::~auto_ptrint (0771159h)可以看到它分别调用了 构造函数 和 析构函数接下来找下 auto_ptr 这两个函数的源码。class auto_ptr {private:_Ty* _Myptr; // the wrapped object pointerpublic:auto_ptr(auto_ptr_ref_Ty _Right) noexcept {_Ty* _Ptr _Right._Ref;_Right._Ref nullptr; // release old_Myptr _Ptr; // reset this}~auto_ptr() noexcept {delete _Myptr;}
}源码一看就明白了在构造函数中将 new int 的地址塞给了内部的 _Myptr 指针在析构函数中对 _Myptr 进行 delete 真好这样就不用整天担心有没有加 delete 啦。值得注意的是现在 C 不推荐这个了而是建议使用新增的shared_ptrunique_ptrweak_ptr, 怎么说呢auto_ptr 有一个不好处理的问题就是现实开发中会出现这么个场景多个 ptr 指向同一个 引用如下图2. auto_ptr 多引用问题方式1定义三个 ptr然后包装同一个 new int 地址参考代码如下void test() {int* i new int(10);auto_ptrint ptr1(i);auto_ptrint ptr2(i);auto_ptrint ptr3(i);
}这种写法有没有问题呢肯定有问题啦还记得 auto_ptr 的析构是 delete 吗对同一块内存多次 delete 会抛异常的如下图所示方式2既然定义三个有问题, 那就用赋值运算符 让 ptr1,ptr2,ptr3 指向同一个地址是不是就可以啦参考代码如下void test() {int* i new int(10);auto_ptrint ptr1(i);auto_ptrint ptr2 ptr1;auto_ptrint ptr3 ptr2;
}int main() {test();
}那这段代码有没有问题呢有没有问题得要看 运算符是如何重写的扒一下源码看看。template class _Other
auto_ptr operator(auto_ptr_Other _Right) noexcept {reset(_Right.release());return *this;
}
_Ty* release() noexcept {_Ty* _Tmp _Myptr;_Myptr nullptr;return _Tmp;
}从源码看有一个很恶心的点,他会将 _Right 下的 _Myptr 设为 nullptr,也就是说此时的 ptr1 报废了言外之意就是后续再访问 ptr1 会抛 访问违例。哈哈C里面的专业术语叫 控制权转移。好了本篇就说这么多吧下一篇聊聊新增的这些关键词看看如何将 auto_ptr 更合理的分权。