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,它可以模仿指针的行为,而且额外提供了一系列诸如自己主动内存管理.边界检查等特性,这些特性是为了在保证效率的基础上降低因为对指针的不 ...
随机推荐
- Libnids---编写网络应用程序的利器
一.前言 Libnids是一个用于网络入侵检测开发的专业编程接口,它使用Libpcap进行数据包的捕获.同时,Libnids提供了TCP/IP数据流重组功能,因此省去了应用层自己考虑数据分片.重传等情 ...
- docker的基本使用
docker 基本的使用命令docker pull centos:latestdocker images centosdocker run -i -t centos /bin/bash //也可以使用 ...
- WORDPRESS插件开发(二)HELLO WORLD改进版
在上一篇文章中WORDPRESS插件开发(一)HELLO WORLD,演示了Hello World的最简单实现,只是在每篇文章的后面加入Hello World字符,而且字符也是写死的. 如果用户需要自 ...
- PHP面向对象的特性
1.抽象性2.封装性3.继承extends4.多态
- python学习笔记enumerate()与range(len)运用及赋值小计
#!/uer/bin/env python # _*_ coding: utf-8 _*_ #格式1 a = 'abc' for i in range(len(a)): print a[i],'(%d ...
- iOS 9适配技巧
中文快速导航: 1.iOS9网络适配_ATS:改用更安全的HTTPS(见Demo1) i. WHAT(什么是SSL/TLS?跟HTTP和HTTPS有什么关系) ii. WHY(以前的HTTP不是也能用 ...
- asp.net学习资源汇总
名称:快速入门地址:http://chs.gotdotnet.com/quickstart/描述:本站点是微软.NET技术的快速入门网站,我们不必再安装.NET Framework中的快速入门示例程序 ...
- iOS之手势滑动返回功能-b
iOS中如果不自定义UINavigationBar,通过手势向右滑是可以实现返回的,这时左边的标题文字提示的是上一个ViewController的标题,如果需要把文字改为简约风格,例如弄过箭头返回啥的 ...
- Stanford CoreNLP--功能列表
Standford CoreNLP包含很多功能,github上有源码,github地址:Stanford CoreNLP,有需要的话可以下载看看. 主要内容在网站上都有描述,原文是这样写的: Choo ...
- 系统的了解DJANGO中数据MODULES的相关性引用
数据库结构如下: from django.db import models class Blog(models.Model): name = models.CharField(max_length=1 ...