weak_ptr指针编程实验
weak_ptr指针编程实验
- 基本知识
- weak_ptr
- 改进后的StrBlob类
- 示例代码
- my_StrBlob.h
- main.cpp
- 运行结果
本文是本人大一期间在校学习C++课程时所撰写的实验报告的摘录,由于刚上大学,刚接触计算机编程方面的相关知识,故可能会有很多不足甚至错误的地方,还请各位看官指出及纠正。
本文所涉及到的“教材”指:
电子工业出版社《C++ Primary中文版(第5版)》
如需转载或引用请标明出处。
基本知识
weak_ptr
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象也还是会被释放,因此,weak_ptr的名字体现了“弱”共享对象的特点。
下面是关于weak_ptr的一些操作:
weak_ptr<T> w //空weak_ptr可以指向类型为T的对象
weak_ptr<T> w(sp) //与shared_ptr sp指向相同对象的weak_ptr。T必须能转换为sp指向的类型
w.reset() //将w值为空
w.lock() //如果与w共享对象的shared_ptr数量为0,则返回一个空shared_ptr;否则返回一个指向w的对象的shared_ptr
更多相关操作详见教材P420,表12.5。
当我们创建一个weak_ptr时,要用一个shared_ptr来初始化它:
auto p = make_shared<int>(99);
weak_ptr<int> wp(p);
由于weak_ptr的“弱”的特性,创建wp并不会增加p的引用计数,因此wp所指向的对象可能会被释放掉。由于对象可能不存在,我们不能使用weak_ptr直接访问对象,因而必须调用weak_ptr的成员函数lock,该函数检查weak_ptr指向的对象是否存在。若存在,lock返回一个指向共享对象的shared_ptr,否则返回一个空的shared_ptr。
改进后的StrBlob类
关于StrBlob类可以看这篇文章。
为了做到不影响给定的StrBlob所指向vector的生存期,同时也可以阻止用户访问一个不再存在的vector的目的,将给以前的StrBlob定义一个伴随指针类StrBlobPtr。该类会保存一个weak_ptr,在初始化时使它指向StrBlob的成员data。
StrBlobPtr有两个数据成员:weak_ptr类型的wptr,指向空或者一个StrBlob中的vector;vector::size_type类型的curr,用于保存当前对象所表示的元素的下标(实际上是给shared_ptr使用的下标)。此外还将有一个成员函数check用于检查解引用StrBlobPtr是否安全,另一个成员函数deref用于解引用对象。
在StrBlob中,添加了两个成员函数begin和end,用于代替普通begin函数和end函数的作用(返回对应的迭代器),新定义的这两个函数将使用StrBlobPtr以免在for循环中改变StrBlob中data的引用计数。为了做到检查指向位置是否合法的同时可以方便地解引用,让StrBlobPtr的成员函数check在检查通过时返回对应的shared_ptr,因此成员函数deref实际上是间接地通过解引用一个shared_ptr来获得weak_ptr指向对象,又因为是在函数中,故不会影响指向对象的生存期
示例代码
my_StrBlob.h
#ifndef MY_STRBLOB_H
#define MY_STRBLOB_H
#include <vector>
#include <string>
#include <memory>
//包含标准库类型initializer_list,以使用有可变形参的函数
#include <initializer_list>
//包含并使用一些标准库异常
#include <stdexcept>using namespace std; class StrBlobPtr; //提前声明,StrBlob中的友类声明所需//定义StrBlob类
class StrBlob
{friend class StrBlobPtr; //友元声明,声明StrBlobPtr是StrBlob的友元//public的成员可被整个程序使用
public:typedef vector<string>::size_type size_type; //定义vector<string>的size_type类型为size_typeStrBlob(); //无形参的构造函数声明StrBlob(initializer_list<string> list); //有可变形参的构造函数声明size_type size() const { return data->size(); } //定义StrBlob的成员函数sizebool empty() const { return data->empty(); } //定义StrBlob的成员函数empty//添加和删除元素的操作void push_back(const string& t) { data->push_back(t); } //定义StrBlob的成员函数push_backvoid pop_back(); //StrBlob的成员函数pop_back的声明 //访问元素的操作string& front(); //StrBlob的成员函数front的声明const string& front() const; //const版本的StrBlob的成员函数front的声明string& back(); //StrBlob的成员函数back的声明const string& back() const; //const版本的StrBlob的成员函数back的声明//提供给StrBlobPtr的接口,定义StrBlobPtr后才能定义这两个函数StrBlobPtr begin(); //StrBlob的成员函数begin的声明StrBlobPtr end(); //StrBlob的成员函数end的声明//private的成员只能被类的成员函数访问
private:shared_ptr<vector<string>> data; //该类只有一个成员:指向存储string的vector的智能指针void check(size_type i, const string& msg) const; //如果data[i]不合法,抛出一个异常,显示msg
};StrBlob::StrBlob() :data(make_shared<vector<string>>()) { } //定义无形参的构造函数
StrBlob::StrBlob(initializer_list<string> list) : data(make_shared<vector<string>>(list)) { } //定义有可变形参的构造函数void StrBlob::check(size_type i, const string& msg) const //check函数的定义
{if (i >= data->size()) //如果i超出vector的范围throw out_of_range(msg); //则抛出异常
}string& StrBlob::front() //普通版本的front函数
{check(0, "front on empty StrBlob"); //如果vector为空,则check抛出一个异常return data->front(); //返回data的成员函数front的返回值(起始元素的引用)
}const string& StrBlob::front() const //const版本的front函数
{check(0, "front on empty StrBlob"); //如果vector为空,则check抛出一个异常return data->front(); //返回data的成员函数front的返回值(起始元素的引用)
}string& StrBlob::back() //普通版本的back函数
{check(0, "back on empty StrBlob"); //如果vector为空,则check抛出一个异常return data->back(); //返回data的成员函数back的返回值(尾元素的引用)
}const string& StrBlob::back() const //const版本的back函数
{check(0, "back on empty StrBlob"); //如果vector为空,则check抛出一个异常return data->back(); //返回data的成员函数back的返回值(尾元素的引用)
}void StrBlob::pop_back() //定义SrtBlob的成员函数pop_back
{check(0, "pop_back on empty StrBlob"); //如果vector为空,则check抛出一个异常data->pop_back(); //返回data的成员函数pop_back的返回值
}class StrBlobPtr
{friend bool eq(const StrBlobPtr& lhs, const StrBlobPtr& rhs); //声明函数eq是StrBlobPtr是的友元函数public:StrBlobPtr() :curr(0) { } //无形参的构造函数定义(弱指针位置指向首元素)StrBlobPtr(StrBlob& a, size_t sz = 0) :wptr(a.data), curr(sz) { } //有形参的构造函数定义(默认位置是首元素) string& deref() const; //StrBlobPtr的成员函数deref的声明StrBlobPtr& incr(); //StrBlobPtr的成员函数incr的声明StrBlobPtr& decr(); //StrBlobPtr的成员函数decr的声明private:weak_ptr<vector<string>> wptr; //成员wptr:一个指向vector<string>的weak_ptrsize_t curr; //成员curr:用于指示vector中的当前位置shared_ptr<vector<string>> check(size_t i, const string& msg) const; //check函数,
};//如果wptr指向的对象不存在,或位置超出vector,则抛出相应的异常
shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string& msg) const
{auto ret = wptr.lock(); //ret是一个指向vector<string>的shared_ptrif (!ret) //如果wptr指向的对象不存在throw runtime_error("unbound StrBlobPtr");if (i >= ret->size()) //如果指向的位置超出vectorthrow out_of_range(msg);return ret; //返回相应的shared_ptr
}string& StrBlobPtr::deref() const //解引用指向当前位置的shared_ptr
{auto p = check(curr, "dereference past end"); //检查当前位置是否合法return (*p)[curr]; //返回当前位置的解引用
}StrBlobPtr& StrBlobPtr::incr() //递增weak_ptr指向的位置
{check(curr, "increment past end of StrBlobPtr");//检查位置curr++; //递增指向位置return *this; //返回当前的StrBlobPtr
}StrBlobPtr& StrBlobPtr::decr()
{curr--; //递减指向位置check(-1, "decrement past begin of StrBlobPtr");//检查位置return *this; //返回当前的StrBlobPtr
}StrBlobPtr StrBlob::begin()
{return StrBlobPtr(*this); //返回一个弱指针指向StrBlob成员data首元素的StrBlobPtr
}//返回一个弱指针指向StrBlob成员data尾元素的StrBlobPtr
StrBlobPtr StrBlob::end()
{auto ret = StrBlobPtr(*this, data->size()); //更改构造函数默认参数为data的大小,使弱指针指向尾元素return ret;
}bool eq(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{auto l = lhs.wptr.lock(), r = rhs.wptr.lock();if (l == r) //如果两个shared_ptr指向同一位置return (!r || lhs.curr == rhs.curr); //则返回ture(r与l可能指向空)elsereturn false;
}bool neq(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{return !eq(lhs, rhs); //上个函数的相反
}#endif
main.cpp
#include <iostream>
#include "my_StrBlob.h" //包含自定义的头文件用双引号int main(void)
{StrBlob b1; //用无形参的构造函数初始化StrBlob类型b1{StrBlob b2({ "China", "America", "Japan" }); //用有可变形参的构造函数初始化StrBlob类型b2b1 = b2; //将b2的值赋给b1b2.push_back("France"); //在b2末尾添加元素“France”cout << b2.size() << endl; //输出b2}//b2的作用域结束,其智能指针的的计数器减一 cout << b1.size() << endl; //使用自定义的成员函数size输出b1的大小cout << b1.front() << " " << b1.back() << endl; //使用自定义的成员函数front、back输出b1的首位两个元素b1.pop_back(); //删除b1的尾元素const StrBlob b3 = b1; //复制一份const的b1给b3,b1智能指针的计数器加一cout << b3.front() << " " << b3.back() << endl; //使用const版本的自定义的成员函数front、back输出b3的首位两个元素for (auto it = b1.begin(); neq(it, b1.end()); it.incr())//使用弱指针遍历b1,以免影响其计数器的值cout << it.deref() << endl;system("pause");return 0;
}
运行结果
weak_ptr指针编程实验相关推荐
- 共享智能指针编程实验
共享智能指针编程实验 基本知识 shared_ptr与make_shared initializer_list 自定义的StrBlob类 const限定符 示例代码 my_StrBlob.h main ...
- 实验六 Linux进程编程,Linux系统编程实验六:进程间通信
<Linux系统编程实验六:进程间通信>由会员分享,可在线阅读,更多相关<Linux系统编程实验六:进程间通信(10页珍藏版)>请在人人文库网上搜索. 1.实验六:进程间通信l ...
- allocator类编程实验
allocator类编程实验 基本知识 allocator uninitialized_copy.uninitialized_fill等函数 示例程序 示例代码 usealloc.cpp useall ...
- 182_赵陈雄_java核心编程实验
Java-核心编程实验课笔记(一) 一:Java特性和优势 1:简单性 2:面向对象 3:可移植性 4:高性能 5:分布式 6:动态性 7:多线程 8:安全性 9:健壮性 二:Java程序运行机制 1 ...
- 实验c语言程序数据类型,C语言编程实验.doc
C语言编程实验.doc C语言程序设计上机安排C语言上机实验32学时序号实验项目名称内容提要学时数1上机操作初步熟悉VC语言上机环境:了解如何编辑.编译.连接和运行一个C程序.22简单的C程序设计掌握 ...
- 计算机编程实验,c语言下的计算机软件编程实验
c语言下的计算机软件编程实验 (5页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.90 积分 C语言下的计算机软件编程实验 摘 要C语言是计算机应用的 ...
- ## ARM基础编程实验
ARM基础编程实验 作者: Saint 掘金:https://juejin.im/user/5aa1f89b6fb9a028bb18966a 微博:https://weibo.com/54582774 ...
- 华中科技大学计算机通信与网络实验,华中科技大学计算机通信与网络实验报告Socket编程实验.docx...
实验一 Socket编程实验 1.1环境 开发环境:Windows 10 64 位,Intel Core i5-7300HQ CPU, 8GB 内存 1.1. 1开发平台 Microsoft Visu ...
- C Primer Plus (第五版) 第十章 数组和指针 编程练习
第十章 数组和指针 编程练习 1.修改程序清单10.7中的程序rain,使它不使用数组下标,而是使用指针进行计算(程序中仍然需要声明并初始化数组). # include <stdio.h> ...
最新文章
- 结构体名和结构体名是个指针的区别
- 【vs开发】向图形界面程序添加控制台
- 机器学习样本标记 示意代码
- 线上直播 | NVIDIA TensorRT在神经机器翻译中的应用
- MVC学习二:基础语法
- 一次性定时器 setTimeout
- 010 editor 应用templates分析ELF和dex文件
- C语言equivalent用法,C语言相当于'setw'函数
- mysql如何创建视图
- mysql 无法创建sock,mysql.sock无法打开的问题
- Linux (deepin)网络管理详解.
- 看懂Python爬虫框架,所见即所得一切皆有可能
- 文学研究助手(设计性实验)
- 【Linux集群教程】12 集群安全防御 - 安全防御概述和Linux防火墙
- 英特尔one API——AI为科技加速
- 高通骁龙845的android手机有哪些,骁龙845手机有哪些?高通骁龙845手机推荐
- 金蝶K3供应链与总账对账的思路及方法
- 如何把照片转换成3D?告这篇文章告诉你
- iOS-基础控件--UITbleViewCell的自定义(高度自适应方法简单封装)
- 计算机游戏设计软件有哪些,除了玩游戏还能做设计?十代酷睿设计软件实操