写时拷贝技术:Copy-On-Write

概念

Copy-On-Write是一种技术——去高效的完成“懒惰行为”。其核心思想就是:只有在需要分配内存的时候才会进行内存分配。这种思想广泛的运用在操作系统和C++编程中。

在操作系统当中,当一个程序运行结束时,操作系统并不会急着把其清除出内存,原因是有可能程序还会马上再运行一次,而只有当内存不够用了,才会把这些还驻留内存的程序清出。这样既尽可能地减少了CPU读取磁盘的次数,又可以保证功能的正确性。

在C++中Copy-On-Write技术被广泛地应用于智能指针和字符串类等地方。例如在QT的框架中,许多类型应用了该技术,QT的术语叫做隐式共享(”implicialy shared”), 通过compare-and-swap 操作增减内部参考计数器来完成操作。因为复制时相对廉价的,所以QT可以经常安全地使用多线程。

目的

  1. 对于某些类而言,每一次都执行深拷贝会极大的降低执行效率,为了提高计算机执行效率
  2. 确保在需要进行深拷贝的时候(内容被改变的时候)执行深拷贝,确保程序的准确性

方法:

设置一个计数器,标明引用的个数,当引用数量为0时,删除该对象:
1. 在对象生命周期结束(调用析构函数)or需要写入的时候,计数器减一
2. 在执行拷贝构造or赋值函数的时候,计数器加一
3. 在赋值函数中,输入的左值将被重新赋值,所以需要将之前所指向的地址的计数器减一

implementation

一个简单的智能指针的实现

#include <iostream>
using namespace std;

template
<typename T>
class CowPtr{
protected:
    struct Ptr{
        T* point;
        unsigned int counter;
    };
    Ptr* ptr;
    void detach();
public:
    CowPtr(const T* p =NULL);

    CowPtr(const CowPtr& cp);
    CowPtr& operator=(const CowPtr& cp);

    unsigned int GetCount() const;
    T* GetPoint() const;

    T& operator *();
    T operator *() const;

    T* operator ->();
    const T* operator ->() const;

    ~CowPtr();




};


template
<typename T>
void CowPtr<T>::detach(){
    if(ptr->counter != 1){
        Ptr* temp = new Ptr;
        temp->point = ptr->point;
        temp->counter = ptr->counter;
        ptr = temp;
    }
}

template
<typename T>
CowPtr<T>::CowPtr(const T* p){
    ptr = new Ptr;
    ptr->point = const_cast<T*>(p);
    ptr->counter = 1;
}

template
<typename T>
CowPtr<T>::CowPtr(const CowPtr<T>& cp){
    ptr = cp.ptr;
    ptr->counter++;
}

template
<typename T>
CowPtr<T>& CowPtr<T>::operator=(const CowPtr<T>& cp){
    if( (this!=&cp)|| (ptr != cp.ptr)){
        if((ptr->counter--) == 0){
            delete ptr->point;
            delete ptr;
        }

        ptr= cp.ptr;
        ptr->counter++; 
    }
    return *this;
}

template
<typename T>
unsigned int CowPtr<T>::GetCount() const{
    return ptr->counter;

}



template
<typename T>
T* CowPtr<T>::GetPoint() const{
    return ptr->point;

}

template
<typename T>
T& CowPtr<T>::operator *(){
    return *(ptr->point);
}

template
<typename T>
T CowPtr<T>::operator *() const{
    return *(ptr->point);
}


template
<typename T>
T* CowPtr<T>::operator ->(){
    return ptr->point;
}

template
<typename T>
const T* CowPtr<T>::operator ->() const{
    return ptr->point;
}



template
<typename T>
CowPtr<T>::~CowPtr(){
    if((--ptr->counter) == 0){
        delete ptr->point;
        delete ptr;
        ptr = NULL;
    }
}

class Test {
    int i;
public:
    Test(){
        cout<<"Test()"<<endl;
    }


    ~Test(){
        cout<<" ~Test()"<<endl;
    }    

};

int main()
{
    CowPtr<Test> cp = new Test;
    cout<<cp.GetPoint()<<endl;
    cout<<cp.GetCount()<<endl;

    CowPtr<Test> cp1 = cp;
    cout<<cp1.GetPoint()<<endl;
    cout<<cp1.GetCount()<<endl;

    CowPtr<Test> cp2;
    cp2 = cp;
    cout<<cp2.GetPoint()<<endl;
    cout<<cp2.GetCount()<<endl;

    printf("Hello World");

    return 0;
}

这个只实现了部分功能,每有一个指针指向共享内存,计数器加一,计数器为0的时候释放内存。但是没有实现在写的时候自动拷贝的功能

猜你喜欢

转载自blog.csdn.net/yzcwansui/article/details/80663682
今日推荐