C++中的淺拷貝、深拷貝、智能指針


淺拷貝(shallow copy)與深拷貝(deep copy)對於值拷貝的處理相同,都是創建新對象,但對於引用拷貝的處理不同,深拷貝將會重新創建新對象,返回新對象的引用字。淺拷貝不會創建新引用類型。


怎么判斷一個類的賦值構造函數的方法:根據類的實現
1。如果它有一個用原生指針指針實現的對象引用,或是用boost::shared_ptr等引用分享所有權的智能指針實現的對象引用,則這個拷貝是淺拷貝
2。如果是用copy_ptr這種實現了深拷貝的智能指針實現的對象引用,就是深拷貝了。copy_ptr在內部保留一個指針,當它自己解析時,它同時也銷毀它在內部保存的這個指針。
最能體現深層拷貝與淺層拷貝的,就是‘=’的重載。我們以此為例。
例1:淺拷貝
class string
{
  char *m_str; //對象之中含有指針數據類型
public:
  string(char *s)
  {
    m_str=s;
  }
  string(){};
  string&operator=(const string s)
  {
    m_str=s.m_str; //s1,s2指向同一個內存
    return *this}
  };
  int main()
  {
    string s1("abc"),s2;
    s2=s1;
    cout<<s2.m_str;
  }
};

 

例2:深拷貝
string&operator=(const string&s)
{
  if(strlen(m_str)!=strlen(s.m_str))
  m_str=new char[strlen(s.m_str)+1]; //為被賦值對象申請了一個新的內存
  if(*this!=s)
    strcmp(m_str,s.m_str);
  return *this;
}

 

淺拷貝易使對象的值發生不必要的改變。這時我們需要智能shared_ptr指針來管理。
例:
#include <vector>
using namespace std;
using namespace boost;
 
int main (int argc, const char * argv[])
{
 
    typedef vector< shared_ptr > sharedContainers;
    sharedContainers sharedArray(10);
    int i=0;
    for(sharedContainers::iterator pos = sharedArray.begin() ;pos!=sharedArray.end();++pos) 
    {
        *pos = make_shared(++i);
    }
    cout<<"sharedArray[5]的初始值:"<<*sharedArray[5]<<endl;
    cout<<"sharedArray[5]的初始引用計數為:"<<sharedArray[5].use_count()<<endl;
    shared_ptr p1 = sharedArray[5];
    *p1 = 10;
    cout<<"sharedArray[5]經過賦值后的值:"<<*sharedArray[5]<<endl;
    cout<<"sharedArray[5]賦值后的引用計數為:"<<sharedArray[5].use_count()<<endl;
    shared_ptr p2(sharedArray[5]);
    cout<<"sharedArray[5]復制后的引用計數為:"<<sharedArray[5].use_count()<<endl;
    return 0;
}
其輸出結果為:
  sharedArray[5]的初始值:6
  sharedArray[5]的初始引用計數為:1
  sharedArray[5]經過賦值后的值:10
  sharedArray[5]賦值后的引用計數為:2
  sharedArray[5]復制后的引用計數為:3
 
shared_ptr簡單實現(主旨:引用計數reference count):

1.一個模板指針T* ptr,指向實際的對象。

2.創建類的新對象時,初始化指針並將引用計數置為1。

3.重載operator*和operator->,使得能像指針一樣使用shared_ptr。

4.重載copy constructor,使其引用次數等於右操作數所指對象加一。

5.重載operator=,如果原來的shared_ptr已經有對象,則讓其引用次數減一並判斷引用是否為零(是否調用delete)。

 然后將新的對象引用次數加一。

6.重載析構函數,使引用次數減一並判斷引用是否為零(是否調用delete)。  

#ifndef __SHARED_PTR_
#define __SHARED_PTR_

template <typename T>
class shared_ptr {
public:
    shared_ptr(T* p) : count(new int(1)), _ptr(p) {}
    shared_ptr(shared_ptr<T>& other) : count(&(++*other.count)), _ptr(other._ptr) {}
    T* operator->() { return _ptr; }
    T& operator*() { return *_ptr; }
    shared_ptr<T>& operator=(shared_ptr<T>& other)
    {
        ++*other.count;
        if (this->_ptr && 0 == --*this->count)
        {
            delete count;
            delete _ptr;
        }
        this->_ptr = other._ptr;
        this->count = other.count;
        return *this;
    }
    ~shared_ptr()
    {
        if (--*count == 0)
        {
            delete count;
            delete _ptr;
        }
    }
    int getRef() { return *count; }
private:
    int* count;
    T* _ptr;
};


#endif

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM