Why do we need smart pointer and how to implement it.
Here are two simple questions.
Problem A
#include <string>
include <iostream>
using namespace std; class vehicle
{
public:
vehicle(const string& name);
virtual ~vehicle(){} void PrintOwnerInfo(); private:
string driver_name_;
}; vehicle::vehicle(const string& name):
driver_name_(name){
} void vehicle::PrintOwnerInfo(){
cout<<driver_name_<<endl;
} int main()
{
string driver_name = "Zhou You";
vehicle* pbicycle = new vehicle(driver_name);
pbicycle->PrintOwnerInfo();
return ;
}
Any problems in the first piece of code?In main function,I produce an vehicle object which is holden by "pbicycle",then I call PrintOwnerInfo to output the name of the driver.The point is I fail to delete the pointer pbicycle which holds an vehicle object,and this is the most common mistake new programmers always make(it calls memory leak).
Look at another piece of code.Problem B
class A
{
public:
A();
A(int num);
~A(){} void PrintNum();
private:
int num_;
}; A::A():num_(){
} A::A(int num):
num_(num){
} void A::PrintNum(){
cout<<num_<<endl;
} int main()
{
A *pa1 = new A();
pa1->PrintNum(); A *pa2 = pa1;//pa2 point to the same object with pa1
pa2->PrintNum(); delete pa1
pa2->PrintNum();//error happens return ;
}
In main function,I produce an object of class A,using pa1 to point to it.With a pointer of this object,I call PrintNum function to print the integer.Now that I have pa1,I want to create another pointer pa2 to point to the same object with pa1.The next thing I want to do is to delete pa1.Can I do that?Nooooo.With this inappropriate statement,I transform pa2 to a dangling pointer.The code above is pretty simple and easy,so we can understand it very quickly and find the drawbacks.But in real projects,such mistakes can be easily made and ignored.Is there any good solutions to avoid it?I mean we don't even need to care about these things.Actually this is part of memory management in C++,we can use smart pointer to help us to handle managing memory issue.
In the vehicle instance,We can write main function with the smart pointer like this.
int main()
{
string driver_name = "John Zhou";
SPvehicle spbicycle = new vehicle(driver_name);
spbicycle->PrintOwnerInfo(); return ;
}
"SPvehicle" is a smart pointer class for vehicle.I do not need to delete it When I finish using this pointer,because this pointer itself has the feature to release its object when it is not useful any more.So how to implement it? Basically,there are two points to take care.
1."spbicycle" should behave like an vehicle pointer does.It should support both dereferencing(*) operation and indirection(->) operation.
2.It should be able to release the object automatically.
Check out the code below.
class SPvehicle
{
public:
SPvehicle(){}
SPvehicle(vehicle *pvehicle);
~SPvehicle(); vehicle& operator*(){
return *pobjvehicle_;
} vehicle* operator->(){
return pobjvehicle_;
}
private:
vehicle *pobjvehicle_;
}; SPvehicle::SPvehicle(vehicle *pvehicle):
pobjvehicle_(pvehicle){
} SPvehicle::~SPvehicle(){
delete pobjvehicle_;
}
In the SPvehicle class,I overload 2 operators(*,->),then I can use it as a normal vehicle pointer.In the destructor,I delete pobjvehicle_ to release the memory space.
Class SPvehicle gives us a solution to manage the object automatically,but still remains problem B unsolved.So how to handle the dangling pointer?The object it points to is released by the other pointer,but it is not informed,and this is the direct reason it becomes dangling.For an object,can we remember the amount of the pointer which point to it?With the amount,we are able to know the right time to release the object(the amount decreasing to 0).Let's try.
class RfCount
{
public:
RfCount(){}
RfCount(unsigned rfc):
rfc_(rfc){
} ~RfCount(){} unsigned AddRef(){
return ++rfc_;
} unsigned CutRef(){
return --rfc_;
} private:
unsigned rfc_;
}; class SPA
{
public:
SPA();
SPA(A *pa);
SPA(const SPA &spa);
~SPA(); A& operator*(){
return *pa_;
} A* operator->(){
return pa_;
} SPA& operator=(const SPA &spa); private:
RfCount* reference_count_;
A *pa_;
}; SPA::SPA():pa_(NULL),
reference_count_(new RfCount()){
cout<<"default SPA constructor."<<endl;
} SPA::SPA(A* pointera):
pa_(pointera),
reference_count_(new RfCount()){
cout<<"SPA constructor1 adds referencecount by 1."<<endl;
reference_count_->AddRef();
} SPA::SPA(const SPA& spa):
pa_(spa.pa_),
reference_count_(spa.reference_count_){
cout<<"SPA constructor2 adds referencecount by 1."<<endl;
reference_count_->AddRef();
} SPA::~SPA(){
cout<<"SPA destructor cut referencecount by 1."<<endl;
if(reference_count_->CutRef() == ){
cout<<"release the object."<<endl;
delete pa_;
}
} SPA& SPA::operator=(const SPA& spa){
if(this != &spa){
cout<<__FUNCTION__<<" "<<"refcount added by 1."<<endl;
reference_count_ = spa.reference_count_;
reference_count_->AddRef();
pa_ = spa.pa_;
}
return *this;
} void copypointer(SPA& spa){
SPA spa1;
spa1 = spa;
spa1->PrintNum();
} int main()
{
SPA spa1 = new A();
spa1->PrintNum();
copypointer(spa1);
spa1->PrintNum();
return ;
}
In main function,I produce a smart pointer spa1 at first(reference count is initialized to 1),then use it to call member function of class A which can prove that I can use this smart pointer as a normal A pointer.The next step is to call copypointer() function and it takes spa1 as the argument.In copypointer(),I reproduce a local smart pointer spa2 which is assigned with spa1(reference count up to 2),during the process of assignment,the referencecount is increased to 2.After function copypointer() finishes its task,spa2 just goes out of scope,and SPA destructor is called.In SPA destructor, referencecount is reduced by 1.Back to main funtion,when main ends up,SPA destructor is called again,and reference count is reduced to 0,and that's exactly the time we need to release A pointer inside class SPA,because there are no pointers referencing this A object.
OK,for problem A and B I post at the start of this article,we just figure out how to solve or avoid them,but the code look not cool.For problem A and B,we have to write 2 smart pointer classes respectively.so how about a generic class to implement the smart pointer.
class RfCount
{
public:
RfCount(){}
RfCount(unsigned rfc):
rfc_(rfc){
} ~RfCount(){} unsigned AddRef(){
return ++rfc_;
} unsigned CutRef(){
return --rfc_;
} private:
unsigned rfc_;
}; template <typename T>
class SP
{
public:
SP();
SP(T *pa);
SP(const SP<T>& sp);
~SP(); T& operator*(){
return *pt_;
} T* operator->(){
return pt_;
} SP& operator=(const SP &sp); unsigned AddRef(){
return reference_count_->AddRef();
} unsigned CutRef(){
return reference_count_->CutRef();
} private:
RfCount* reference_count_;
T *pt_;
}; template <typename T>
SP<T>::SP():pt_(NULL),
reference_count_(new RfCount()){
cout<<"default SP constructor."<<endl;
} template <typename T>
SP<T>::SP(T *pt):
pt_(pt),
reference_count_(new RfCount()){
cout<<"SP constructor1 adds referencecount by 1."<<endl;
reference_count_->AddRef();
} template <typename T>
SP<T>::SP(const SP<T>& sp):pt_(sp.pt_),
reference_count_(sp.reference_count_){
cout<<"SP constructor2 adds referencecount by 1."<<endl;
reference_count_->AddRef();
} template <typename T>
SP<T>::~SP(){
cout<<"SP destructor cut referencecount by 1."<<endl;
if(reference_count_->CutRef() == ){
cout<<"release the object."<<endl;
delete pt_;
}
} template <typename T>
SP<T>& SP<T>::operator=(const SP &sp){
if(this != &sp){
reference_count_ = sp.reference_count_;
cout<<__FUNCTION__<<" "<<"refcount added by 1."<<endl;
reference_count_->AddRef();
pt_ = sp.pt_;
}
return *this;
} void copypointer(SP<A>& spa){
SP<A> spa1;
spa1 = spa;
spa1->PrintNum();
} int main()
{
SP<A> spa1 = new A();
spa1->PrintNum();
copypointer(spa1);
spa1->PrintNum();
return ;
}
Using template,we can write a generic smart pointer class.
//词汇拙计啊,乃们就将就看吧,有啥问题给俺指正出来呀。
Why do we need smart pointer and how to implement it.的更多相关文章
- [CareerCup] 13.8 Smart Pointer 智能指针
13.8 Write a smart pointer class. A smart pointer is a data type, usually implemented with templates ...
- 理解smart pointer之三:unique_ptr
unique_ptr最先在boost中被定义,后来被C++标准委员会选中为C++11的feature之一. std::unique_ptr is a smart pointer that retain ...
- c++ smart pointer
智能指针(smart pointer)是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露.它的一种通用实现技术是使用引用计数(reference ...
- c++(smart pointer)
(一)首先对智能指针有一些概念性的了解 **********本部分内容摘自开源中国社区http://my.oschina.net/u/158589/blog/28994******** 1.什么是智能 ...
- c/c++ 标准库 智能指针( smart pointer ) 是啥玩意儿
标准库 智能指针( smart pointer ) 是啥玩意儿 一,为什么有智能指针??? c++程序员需要自己善后自己动态开辟的内存,一旦忘了释放,内存就泄露. 智能指针可以帮助程序员"自 ...
- C++ smart pointer智能指针
在C++中,程序员可以直接操作内存,给编程增加了不少的灵活性.但是灵活性是有代价的,程序员必须负责自己负责释放自己申请的内存,否则就会出现内存泄露.智能指针就是为了解决这个问题而存在的.它和其他指 ...
- Effective C++ Item 17 Store newed objects in smart pointer in standalone statements
If you trying to do multiple things in one statement, you should think carefully abnormal behavior e ...
- Smart pointer 智能指针小总结
Smart pointer line 58之后smart pointer里的计数已经是0,所以会真正释放它引用的对象,调用被引用对象的析构函数.如果继续用指针访问,会出现如下图的内存访问异常.所以说如 ...
- smart pointer
smart pointer是一种abstract data type,它可以模仿指针的行为,而且额外提供了一系列诸如自己主动内存管理.边界检查等特性,这些特性是为了在保证效率的基础上降低因为对指针的不 ...
随机推荐
- nginx 自定义代理返回 404
在nginx的http段,加上一面的配置 proxy_intercept_errors on;//自定义代理返回的404错误提示
- 【原创】Android开发使用华为手机调试logcat没有应用输出信息
输入 *#*#2846579#*#* 点击project Menu点击后台 1.设置logcat 2. Dump & Log",打开开关"打开Dump & Log& ...
- H5小内容(二)
音视频处理 视频处理 基本内容 使用Flash技术处理HTML页面中的视频内容 包含音频.动画.网页游戏等 特点 浏览器原生不支持(IE浏览器要求安装A ...
- Linux下使用openvpn客户端
安装 root 权限用户下 :yum install openvpn fedora23的yum可能会切换到dnf源上安装不必在意,等待就ok. 稍等片刻将自动安装好openvpn需要的软件包.安装完成 ...
- Lucene4.9学习笔记——Lucene建立索引
基本上创建索引需要三个步骤: 1.创建索引库IndexWriter对象 2.根据文件创建文档Document 3.向索引库中写入文档内容 这其中主要涉及到了IndexWriter(索引的核心组件,用于 ...
- css常用伪类记录
1.超链接使用css伪类设置颜色 a:link {color: #000000} /* 未访问的链接 */a:visited {color: #d90a81} /* 已访问的链接 */a:hover ...
- Centos开启FTP及用户配置
vsftpd作为FTP服务器,在Linux系统中是非常常用的.下面我们介绍如何在centos系统上安装vsftp. 什么是vsftpd vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序 ...
- Rsync和FastDFS
在做分布式文件存储的时候,常常用到两个工具,Rsync和FastDFS:这两者本质的区别在于前者的实时性相面相对较差,需要手工编写脚本同步,然后在放到定时任务(cron)中:FastDFS自动实现同组 ...
- C# aspnetpager分页
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs& ...
- EF4 Code First和EF6 Code First链接mysql的方法
1.首先需要下载安装.Net的Mysql驱动 下载地址如下:http://dev.mysql.com/downloads/connector/net/ 2.配置Web.Config EF6: 配置链接 ...