C++基于模板实现智能指针

news/2024/10/7 4:25:52

某厂面试,当时反正是没写出来,估计是寄了,事后做个记录。

#include <iostream>
#include <mutex>
using namespace std;class ObjectElement {
private:char *addr;int size;void release() {addr = nullptr;size = 0;}public:ObjectElement(int size) {cout<< "construct: "<<this<<endl;this->size = size;addr = new char[size];}~ObjectElement() {cout<< "release: "<<this<<endl;delete []addr;release();}void PrintTest() {cout<<"ObjectElement"<<endl;}};// 注意不是线程安全的,需要加锁template <typename T>
class SharedPtr {
private:// 可以用一个额外的ControlBlock 结构存储以下两个私有变量,此处只需要一个指针,做不做两可T *ptr;int *ref_count; // 核心,如果直接用int:每个shared_ptr 就会有自己的引用计数器,它们不会同步更新void release() { // privateif(ref_count != nullptr && --(*ref_count) == 0) {delete ptr;delete ref_count;}}public:SharedPtr() : ptr(nullptr), ref_count(nullptr) {}explicit SharedPtr(T *p) {ptr = p;ref_count = new int(1);}// 注意只有在拷贝或者赋值的时候才会有引用计数的增加// 拷贝构造,增加引用计数SharedPtr(const SharedPtr &s) noexcept {ptr = s.ptr;ref_count = s.ref_count;if(ref_count != nullptr) {(*ref_count)++;}}// 移动构造,没有增加引用计数SharedPtr(SharedPtr &&s) noexcept {ptr = s.ptr;ref_count = s.ref_count;s.ptr = nullptr;s.ref_count = nullptr;}// 拷贝赋值运算符,与拷贝构造类似,但是需要先判断是否是自己,注意返回自身引用SharedPtr& operator=(const SharedPtr &s) noexcept{if(this == &s) {release(); // 重要!删除原有的ptr = s.ptr;ref_count = s.ref_count;if(ref_count != nullptr) {(*ref_count)++;}}return *this;}// 移动赋值运算符,同理SharedPtr& operator=(SharedPtr &&s) noexcept{if(this == &s) {release(); // 重要!删除原有的ptr = s.ptr;ref_count = s.ref_count;s.ptr = nullptr;s.ref_count = nullptr;}return *this;}// 解引用,重载*,返回T对象T& operator*() const {return *ptr;}// 重载指针操作符,使得可以类似->调用T* operator->() const{return ptr;}// 获取裸指针,同上T* get() const{return ptr;}int use_count() const {return (ref_count!=nullptr?(*ref_count):0);}void reset(T* p = nullptr) {release();ptr = p;if(p == nullptr) {ref_count = nullptr;}else {ref_count = new int(1);}}~SharedPtr() {release();}};int main() {ObjectElement *obj = new ObjectElement(100);SharedPtr<ObjectElement> sptr1(obj);SharedPtr<ObjectElement> sptr2 = sptr1;cout<<sptr1.use_count()<<endl;cout<<sptr2.use_count()<<endl;(*sptr1).PrintTest();sptr1->PrintTest();sptr1.get()->PrintTest();sptr1.reset();cout<<sptr1.use_count()<<endl;cout<<sptr2.use_count()<<endl;return 0;
}

预期输出为:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/54506.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

cf补题计划_Edu 162_E

E. Count Paths 题目简介乍一眼一看是一个很简单树上dp(实际上也是树上dp 第一看做法是考虑dp[i][j]表达为第i个节点的下面有多少个颜色为j的节点,且这个节点于i节点之间无其他的节点为j颜色,然后dp转移十分的简单,但是n是\(2\cdot10^5\),绝对超时 然后显然我们发现,一个节…

Operating Systems: Principles and Practice 2nd ed. Edition

https://recursivebooks.com/ Operating Systems: Principles and Practice 2nd ed. Editionby Thomas Anderson (Author), Michael Dahlin (Author)https://www.kea.nu/files/textbooks/ospp/

Vue 3 路由组件缓存keep-alive

Vue 3 路由组件缓存 Vue3 KeepAlive官方文档 1. keep-alive 基本介绍keep-alive 是 Vue 的内置组件,用于缓存动态组件或路由组件,避免组件被频繁销毁和重建,从而提高性能。 当组件被 keep-alive 包裹后,在路由切换时不会销毁组件,而是将其缓存起来。下次切换回来时,会直接…

全网最适合入门的面向对象编程教程:41 Python 常用复合数据类型-队列(FIFO、LIFO、优先级队列、双端队列和环形队列)

在 Python 中,队列(Queue)是一种常用的数据结构,用于按照特定的顺序存储和访问数据。队列的主要类型包括先进先出(FIFO)、后进先出(LIFO)、优先级队列、双端队列(Deque)和环形队列,每种队列在不同的应用场景中都有其独特的用途。全网最适合入门的面向对象编程教程:…

基于 INFINI Pizza 为 Hugo 静态站点添加搜索功能

INFINI Pizza 是 INFINI Labs 即将发布的一个基于 Rust 编写的搜索引擎(即将完全开源),目前已经完成基本的搜索能力,并且基于 INFINI Pizza 的核心引擎,提供了一个 WASM 版本的超轻量级内核,可以很方便的嵌入到各类应用系统,比如网站,尤其是静态站点或者小型的博客系统…

VulNyx - Internal

扫描发现有三个端口basic验证需要用户名密码登录访问80端口 \URLFinder 发现有个internal的php文件看看有无任意文件读取漏洞发现没有回显 但是总感觉怪怪的 应该是有啥东西 因为他这里的出现了pre 标签也许他是过滤了../ 我们改成....//试试真的读取到了通过读取passwd发现有个…

财务知识-会计科目

财务知识-会计科目

【JAVA开发】JDBC链接各大数据库(纯代码)

原创 OA圈子在开发中,我们有时候会涉及到链接第三方数据库视图或者中间库,此时我们需要在OA代码中去创建相应的链接工具类,下面我们分享链接工具类的方法: 链接工具类: import com.seeyon.ctp.common.AppContext; import java.sql.*;public class JdbcUtil {private stat…