My understanding about smart pointer

  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 0;
 }

  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_(0){
}

A::A(int num):
    num_(num){
}

void A::PrintNum(){
    cout<<num_<<endl;
}

int main()
{
    A *pa1 = new A(10);
    pa1->PrintNum();

    A *pa2 = pa1;//pa2 point to the same object with pa1
    pa2->PrintNum();

    delete pa1
    pa2->PrintNum();//error happens

    return 0;
}

  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 is 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 0;
}

  "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 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 point 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 can know when 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(0)){
            cout<<"default SPA constructor."<<endl;
    }

SPA::SPA(A* pointera):
    pa_(pointera),
    reference_count_(new RfCount(0)){
    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() == 0){
        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(10);
    spa1->PrintNum();
    copypointer(spa1);
    spa1->PrintNum();
    return 0;

    return 0;
}

  In main function,I produce a smart pointer spa1 at first(pointercount 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 its param is right spa1.In copypointer(),I reproduce a local smart pointer spa2 which is assigned with spa1(pointercount 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 pointercount 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 the problem A and B we post at the start of this article,we just figure out how to solve or avoid them,but the code look not very 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(0)){
        cout<<"default SP constructor."<<endl;
    }

template <typename T>
SP<T>::SP(T *pt):
    pt_(pt),
    reference_count_(new RfCount(0)){
    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() == 0){
        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(10);
    spa1->PrintNum();
    copypointer(spa1);
    spa1->PrintNum();

    return 0;
}

  Using template,we can write a generic smart pointer class.

  //好久不用英语了,词汇拙计啊,乃们就将就看吧,有啥问题给俺指正出来呀。

My understanding about smart pointer

时间: 2024-10-06 17:00:47

My understanding about smart pointer的相关文章

smart pointer

smart pointer是一种abstract data type,它能够模仿指针的行为,并且额外提供了一系列诸如自动内存管理.边界检查等特性,这些特性是为了在保证效率的基础上减少由于对指针的不正常使用而带来的bug.smart pointer能够自动进行object的销毁:当某个object的最后一个拥有者被destroy的时候(如局部变量离开了作用域),由smart pointer管理的object会被自动销毁.smart pointer是被声明在stack中的 在C++中,smart p

[C++] smart pointer

写在前面的话: 智能指针的设计意图:C++没有垃圾回收机制,所有的动态内存释放全部由程序员负责,如果程序员没有释放内存,就会造成内存泄漏,这是C++ BUG的一大来源.为了管理动态内存,引入了智能指针,它是一种行为类似指针的类,但是能够管理自己负责的内存区域,当对象离开作用域时能够释放内存,防止内存泄漏. 现在常用的C++标准是C++98,其中只定义了一种智能指针auto_ptr. boost中早就引入了其它类型的智能指针:scoped_ptr,scoped_array,shared_ptr,s

Smart pointer 智能指针小总结

Smart pointer line 58之后smart pointer里的计数已经是0,所以会真正释放它引用的对象,调用被引用对象的析构函数.如果继续用指针访问,会出现如下图的内存访问异常.所以说如果选择了用智能指针,就不要再试图用其他方式再去访问对象了. 1 // sharedTest.cpp : Defines the entry point for the console application. 2 // 3 4 #include "stdafx.h" 5 #include

C++ smart pointer智能指针

  在C++中,程序员可以直接操作内存,给编程增加了不少的灵活性.但是灵活性是有代价的,程序员必须负责自己负责释放自己申请的内存,否则就会出现内存泄露.智能指针就是为了解决这个问题而存在的.它和其他指针没有本质的区别,主要的目的就是为了避免悬挂指针.内存泄露的问题.在这里,我使用对象的应用计数做了一个smart pointer,当一个对象还有引用的时候,就不执行释放内存的操作,当引用计数为0时,就执行内存释放操作,并且将指针重置为NULL. 代码如下: #include <iostream>

[CareerCup] 13.8 Smart Pointer 智能指针

13.8 Write a smart pointer class. A smart pointer is a data type, usually implemented with templates, that simulates a pointer while also providing automatic garbage collection. It automatically counts the number of references to a SmartPointer<T*>

【C++】智能指针(Smart Pointer)

1. 传统指针存在的问题 传统指针存在诸多的问题,比如指针所指向的对象的生命周期问题,挂起引用(dangling references),以及内存泄露(memory leaks). 如下是一个传统指针的使用过程 void Foo() { int *iPtr = new int[5]; // manipulate the memory block // ... // ... // ... delete[] iPtr; } 以上代码将正常运行且内存将被合理释放,但是使用指针常会发生一些意想不到的事情

boost smart pointer

1. boost::scoped_ptr is a smart pointer that is the sole owner of a dynamically allocated object and cannot be copied or moved. #include <boost/scoped_ptr.hpp> #include <iostream> int main() { boost::scoped_ptr<int> p(new int(1)); std::c

智能指针(smart pointer)(2):unique_ptr

Unique pointer: Manages the storage of a pointer, providing a limited garbage-collection facility, with little to no overhead over built-in pointers (depending on the deleter used). These objects have the ability of taking ownership of a pointer: onc

智能指针(smart pointer)(1):auto_ptr

智能指针解决了资源生存期管理的问题(尤其是动态分配的对象).智能指针有各种不同的风格.多数都有一种共同的关键特性:自动资源管理.这种特性可能以不同的方式出现:如动态分配对象的生存期控制,和获取及释放资源 (文件, 网络连接).这里主要讨论第一种情况,它们保存指向动态分配对象的指针,并在正确的时候删除这些对象. 何时我们需要智能指针? 有三种典型的情况适合使用智能指针: ? 资源所有权的共享 ? 要写异常安全的代码时 ? 避免常见的错误,如资源泄漏 共享所有权,当多个对象需要同时使用第三个对象的情