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.的更多相关文章

  1. [CareerCup] 13.8 Smart Pointer 智能指针

    13.8 Write a smart pointer class. A smart pointer is a data type, usually implemented with templates ...

  2. 理解smart pointer之三:unique_ptr

    unique_ptr最先在boost中被定义,后来被C++标准委员会选中为C++11的feature之一. std::unique_ptr is a smart pointer that retain ...

  3. c++ smart pointer

    智能指针(smart pointer)是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露.它的一种通用实现技术是使用引用计数(reference ...

  4. c++(smart pointer)

    (一)首先对智能指针有一些概念性的了解 **********本部分内容摘自开源中国社区http://my.oschina.net/u/158589/blog/28994******** 1.什么是智能 ...

  5. c/c++ 标准库 智能指针( smart pointer ) 是啥玩意儿

    标准库 智能指针( smart pointer ) 是啥玩意儿 一,为什么有智能指针??? c++程序员需要自己善后自己动态开辟的内存,一旦忘了释放,内存就泄露. 智能指针可以帮助程序员"自 ...

  6. C++ smart pointer智能指针

      在C++中,程序员可以直接操作内存,给编程增加了不少的灵活性.但是灵活性是有代价的,程序员必须负责自己负责释放自己申请的内存,否则就会出现内存泄露.智能指针就是为了解决这个问题而存在的.它和其他指 ...

  7. 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 ...

  8. Smart pointer 智能指针小总结

    Smart pointer line 58之后smart pointer里的计数已经是0,所以会真正释放它引用的对象,调用被引用对象的析构函数.如果继续用指针访问,会出现如下图的内存访问异常.所以说如 ...

  9. smart pointer

    smart pointer是一种abstract data type,它可以模仿指针的行为,而且额外提供了一系列诸如自己主动内存管理.边界检查等特性,这些特性是为了在保证效率的基础上降低因为对指针的不 ...

随机推荐

  1. Linux网络设置高级指南

    from:http://www.oschina.net/question/23734_117144 Linux网络设置高级指南 本文面向的是被Linux复杂的有线无线网络架构弄得头昏脑胀:或者被网上半 ...

  2. sar监控系统状态

    sar 命令很强大,它可以监控系统所有资源状态,比如平均负载.网卡流量.磁盘状态.内存使用等等. 它不同于其他系统状态监控工具的地方在于,它可以打印历史信息,可以显示当天从零点开始到当前时刻的系统状态 ...

  3. crontab与环境变量

    一个shell脚本,直接执行能成功,但是加在crontab后确怎么也执行不成功. 问题的原因是:crontab的环境变量与直接执行用户的环境变量不一样. export PATH=$PATH:/sbin ...

  4. CentOS6.4 使用谷歌Chromium浏览器

    那么,如果希望在CentOS/RHEL 7出来之前继续使用Chrome怎么办?使用Chrome的开源版本:Chromium. 1.切换到root: su - 或者 sudo -i 2.下载新的软件源定 ...

  5. php图片上传代码

    使用copy函数 if (!empty($_FILES)) { //图片 if(isset($_FILES['image'])) { $img_data = $_FILES['image']['tmp ...

  6. 解决treeview的同一节点单击多次的执行问题

    在使用treeview的AfterSelect函数的时候,单击同一节点多次无响应. 解决方法: 将首次单击的节点信息保存到selectTreeNode: 然后使用click函数,判断单击的节点是否和s ...

  7. 数位dp入门 hdu2089 不要62

    数位dp入门 hdu2089 不要62 题意: 给定一个区间[n,m] (0< n ≤ m<1000000),找出不含4和'62'的数的个数 (ps:开始以为直接暴力可以..貌似可以,但是 ...

  8. HTML DOM Select 对象

    Select 对象 Select 对象代表 HTML 表单中的一个下拉列表. 在 HTML 表单中,<select> 标签每出现一次,一个 Select 对象就会被创建. 您可通过遍历表单 ...

  9. delphi xe5 android 手机上使用sqlite

    本篇我们介绍一下在android手机上怎样使用sqlite数据库,这里用Navigator实现 增删改查. 1.新建firemonkey mobile application 2.选择blank ap ...

  10. simhash--文本排重

    转载自 https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/06.12.md http: ...