C++智能指针初学小结
本篇随笔仅作为个人学习《C++ Primer》智能指针一节后的部分小结,抄书严重,伴随个人理解。主要介绍shared_ptr、make_shared、weak_ptr的用法和联系。
C++通过一对运算符 new 和 delete 进行动态内存管理,new在动态内存中为对象分配空间并返回一个指向该对象的指针,delete接受一个动态对象的指针,销毁对象并释放与之相关的内存。然而这样的动态内存的使用很危险,因为无法确保始终能在合适的时间释放内存对象。如果忘记释放内存,可能造成内存泄露;如果在尚有指针引用内存的情况下释放内存,会产生非法访问内存的指针。
C++11中,新的标准库提供了两种智能指针(smart pointer)类型来更安全地管理对象。智能指针的使用和常规指针类似,只是它们多了自动释放所指向的对象的功能。两种指针的区别在于管理底层指针的方式:shared_ptr允许多个指针指向同一个对象,unique_ptr不支持。标准库还提供了weak_ptr这一弱指针,指向shared_ptr所管理的对象。三种类型都定义在头文件memory中。
shared_ptr的使用和vector很相似,在尖括号内说明所指向对象的类型:
shared_ptr<string> p1 // p1是shared_ptr,指向string类型
shared_ptr<list<int>> p2 // p2是shared_ptr,指向list的int
解引用一个智能指针就能获得它所指向的对象,在if语句中使用智能指针可以判断它指向的对象是否为空:
// 如果p1非空,检查p1是否指向一个空的string对象
if (p1 && p1->empty())
*p1 = "creat"; // 如果p1非空且指向一个空的string对象,解引用p1,为其赋新值creat
最安全的分配和使用shared_ptr的方法是调用名为make_shared这一标准库函数。此函数在动态内存中分配并初始化它,返回指向此对象的shared_ptr。该函数定义在memory中。
make_shared的定义和shared_ptr相似,必须制定要创建对象的类型,如:
// 指向一个值为1的int的shared_ptr
shared_ptr<int> p3 = make_shared<int>)();
// 指向一个值为“www”的string的shared_ptr
shared_ptr<string> p4 = make_shared<string>(, "w");
// 指向一个初始化的int,值为0
shared_ptr<int> p5 = make_shared<int>)();
也可以使用auto定义对象保存make_shared,可以省去书写shared_ptr的麻烦。
shared——ptr中有一个关联的指示器,称为引用计数。可以看做一个计数器,每当shared_ptr对象进行拷贝操作,如用一个shared_ptr对象初始化另一个shared_ptr对象、作为函数的实参、作为函数返回值时,引用计数都会递增(视为数值+1)。当赋予shared_ptr新值或者shared_ptr被销毁时,引用计数递减。当引用计数减为0,通过析构函数,shared_ptr自动销毁所管理的对象,释放内存。
需要注意的是,如果多个对象共享底层数据,当某一对象被销毁,不能单方面销毁底层数据,例如:
Blob<string> b1;
{ // 新作用域
Blob<string> b2 = { "x", "b", "b" };
b1 = b2;
} // 当离开局部作用域,b2被销毁,然而b2中的元素xbb并不会被销毁
// b1指向最初由b2创建的元素,即“x”, "b", "b",b1依旧可以它们
weak_ptr是指向shared_ptr管理的对象的一种智能指针,然而它不控制所指向对象的生存期。将一个weak_ptr绑定在shared_ptr上,不会改变shared_ptr的引用计数,一旦最后一个shared_ptr的指向对象被摧销毁,对象就会被释放,有无weak_ptr并无卵影响。我的理解是,weak_ptr提供了指向shared_ptr底层数据的功能,控制了shared_ptr对底层数据的访问。
因为weak_ptr指向的对象可能不存在(shared_ptr指向的最后一个对象被销毁时),因而用它不能直接访问对象,必须调用lock函数检查其指向的对象是否存在。很容易写出一个选择语句进行控制:
auto bb = make_shared<string>(, 'b');
weak_ptr<string> xbb(bb);
if (shared_pr<int> np = xbb.lock()) { // np不为空条件成立
// 在if语句内,np和xbb共享对象
}
补充weak_ptr相关的函数,便于理解:
w.reset | 将w置为空 |
w.use_count() | 与w共享对象的个数 |
w.expired() | 若w.use_count()为0,返回true,否则返回false |
w.lock() | 若w.expired()为true,返回一个空shared_ptr,否则返回一个指向w的对象的shared_ptr |
加入《C++ Primer 5th》中的12.19题参照,题中和“智能指针和异常”并未在本篇随笔中介绍
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <initializer_list>
using namespace std;
using std::string;
using std::vector;
class StrBlobPtr;
class StrBlob {
public:
friend class StrBlobPtr; // 友元
StrBlobPtr begin(); // 声明StrBlob类中的begin()和end()
StrBlobPtr end(); // 返回一个指向它自身的StrBlobPtr
public:
typedef vector<string>::size_type size_type; // 类型别名,size_type = vector<string>::size_type StrBlob::StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}; // 接受一个initializer_list参数的构造函数将其参数传 递给对应的vector构造函数,通过拷贝列表
StrBlob::StrBlob() : data(make_shared<vector<string>>()) {}; // 构造函数,初始化data成员,指向动态分配的vector 中的值初始化vector元素
void push_back(const string &t) { data->push_back(t); }
string& StrBlob::front() {
check(, "front on empty StrBlob");
return data->front();
}
string& StrBlob::back() {
check(, "back on empty StrBlob");
return data->back();
}
void StrBlob::pop_back() { // 删除尾元素
check(, "pop_back empty StrBlob");
return data->pop_back();
}
string& front() const { return data->front(); };
string& back() const { return data->back(); };
private:
shared_ptr<vector<string>> data;
void StrBlob::check(size_type i, const string &msg) const { // 检查元素是否存在
if (i >= data->size()) // 若不存在
throw out_of_range(msg); // 抛出异常
}
};
class StrBlobPtr {
public:
StrBlobPtr() : curr() {};
StrBlobPtr(StrBlob &a, size_t sz = ) : wptr(a.data), curr(sz) {};
string & deref() const {
auto p = check(curr, "dereference past end");
return (*p)[curr]; // check成功,返回一个p指针,指向make_shared指向的vector
} // 解引用,make_shared获取vector,用下表运算符返回curr位置上的对象
StrBlobPtr& incr() {
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
bool operator!=(const StrBlobPtr& p) { return p.curr != curr; } private:
weak_ptr<vector<string>> wptr;
size_t curr;
shared_ptr<vector<string>> check(size_t i, const string& msg) const
{
auto rent = wptr.lock();
if (!rent)
throw runtime_error("unbound StrBlobPtr");
if (i >= rent->size())
throw out_of_range(msg);
return rent;
}
};
StrBlobPtr StrBlob::begin()
{
return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end()
{
return StrBlobPtr(*this, data->size());
}
C++智能指针初学小结的更多相关文章
- C++智能指针管理类
1.程序员明确的进行内存释放 对于c++程序员,最头脑的莫过于对动态分配的内存进行管理了.c++在堆上分配的内存,需要程序员负责对分配的内存进行释放.但有时内存的释放看起来并不件很轻松的事,如下程序 ...
- 【C++深入浅出】智能指针之auto_ptr学习
起: C++98标准加入auto_ptr,即智能指针,C++11加入shared_ptr和weak_ptr两种智能指针,先从auto_ptr的定义学习一下auto_ptr的用法. template& ...
- Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6786239 Android 系统的运行时库层代 ...
- Effective C++(17) 以独立语句将newed对象置入智能指针
问题聚焦: 使用了资源管理对象(如智能指针),就一定是安全的吗?显然不是. 资源泄露发生可能在于,在“资源被创建”和“资源被转换为资源管理对象”两个时间点之间有可能发生异常干扰. 看下 ...
- C++11智能指针 share_ptr,unique_ptr,weak_ptr用法
0x01 智能指针简介 所谓智能指针(smart pointer)就是智能/自动化的管理指针所指向的动态资源的释放.它是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动 ...
- ZT自老罗的博客 Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析
Android系统的智能指针(轻量级指针.强指针和弱指针)的实现原理分析 分类: Android 2011-09-23 00:59 31568人阅读 评论(42) 收藏 举报 androidclass ...
- C++解析(27):数组、智能指针与单例类模板
0.目录 1.数组类模板 1.1 类模板高效率求和 1.2 数组类模板 1.3 堆数组类模板 2.智能指针类模板 2.1 使用智能指针 2.2 智能指针类模板 3.单例类模板 3.1 实现单例模式 3 ...
- C++解析(20):智能指针与类型转换函数
0.目录 1.智能指针 2.转换构造函数 3.类型转换函数 4.小结 1.智能指针 内存泄漏(臭名昭著的Bug): 动态申请堆空间,用完后不归还 C++语言中没有垃圾回收机制 指针无法控制所指堆空间的 ...
- C++中的智能指针类模板
1,智能指针本质上是一个对象,这个对象可以像原生的指针一样使用,因为智能指 针相关的类通过重载的技术将指针相关的操作符都进行了重载,所以智能指针对象可以像原生指针一样操作,今天学习智能指针类模板,通过 ...
随机推荐
- 创建C#DLL
1. 创建classlibrary 2.编写一个COM接口和一个COM类 [Guid("DBE0E8C4-1C61-41f3-B6A4-4E2F353D3D05")] public ...
- pure.css 学习记录
兼容性记录: IE 8+ Latest Stable: Firefox, Chrome, Safari iOS 6-8 Android 4.x 处理兼容性 <!--[if lte IE 8]&g ...
- ios晃动检测
ios晃动检测 第一种 1.在AppDelegate.h中进行如下设置: - (BOOL)application:(UIApplication *)application didFinishLaun ...
- lua好久没有用了
lua好久没有用了, 最近用python有点多,现在用web.py搞个简单的页面来作通讯录,没美工,很纯白的, 无聊啊,准备去睡了,刚刚百度完lua的一些资料呢, google用不了,真悲剧啊, TM ...
- DOM commend
var comment = document.createComment("commend content"); var elem = document.getElementByI ...
- 深入理解7816(3)-----关于T=0
卡片和终端之间的数据传输是通过命令响应的方式进行的,卡片只能被动地接收命令,并且给出响应.所有的命令都是以命令头开始,而该命令被完整地执行后(无论结果对错),必须以包含状态字(SW1 SW2)的响应结 ...
- Struts2配置RESULT中TYPE的参数说明
chain 用来处理Action链,被跳转的action中仍能获取上个页面的值,如request信息. com.opensymphony.xwork2.Acti ...
- rpm -qs查看包信息
rpm -qs mysql-connector-c-devel Query options (with -q or --query): -c, --configfiles ...
- iOS - Usage of NSData
Reference link : https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/BinaryData/T ...
- Android 读取手机SD卡根目录下某个txt文件的文件内容
1.先看activity_main.xml文件: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/and ...