深浅拷贝与引用计数

其实本文重点想说一下引用计数,但是在说引用计数之前要说明一下深浅拷贝

深浅拷贝是对象调用拷贝构造函数的形式

当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数:
(1)一个对象以值传递的方式传入函数体
(2)一个对象以值传递的方式从函数返回
(3)一个对象需要通过另外一个对象进行初始化。

如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝。

自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。

首先看一个程序例子:

#include <iostream>
using namespace std;

class Example {
private:
    int a;
public:
    Example(int b)
    { a=b;}
	
    Example(const Example& C)
    {
        a=C.a;
    }
    void Show ()
    {
        cout<<a<<endl;
    }
};

int main()
{
    Example A(100);
    Example B=A;
    B.Show ();
    return 0;
}
对于上边的拷贝构造执行默认的按位拷贝对于int型不需要很大的内存,所以可以直接拷贝,所以简称为浅拷贝

具体解释看下图:

再看一个深拷贝的例子:

#include <iostream>
using namespace std;

class A
{
public:
	A(char *str)
	{
		if(str == NULL)
		{
		s = new char[1];
		s[0]='\0';
		}
		else
		{
			s = new char[strlen(str)+1];
			strcpy(s,str);
		}
	}
	A(const A& c)
	{
		s = new char[strlen(c.s)+1];
		if(s)
		{
       strcpy(s,c.s);
		}
	}
	void show()
	{
		cout<<s<<endl;
	}
	~A()
	{
		delete s;
	}
private:
	char *s;
};

void main()
{
	A a("hello");
	A b =a;
	b.show();

}
关于深拷贝请看下图:

下来对于引用计数就是在拷贝的时候每次都使用浅拷贝就是将多个对象中的指针数据指向同一个内存空间,当引用计数为0的时候就进行释放这个空间,其余都是进行引用计数的增加或减少。但是这里存在一个问题,当多个对象使用这个内存的时候就会出现数据一个对象改变后(有点静态数据的意思haha)其他对象访问的内存中数据也是改变后的,所以其中加上了当引用计数大于1的时候(也即是多个对象使用这块内存)如果某个对象需要改变该内存的值,就必须进行深拷贝,就是新分配一块一样的空间拷贝一样的数据从而自己改变,自己拥有,而其他对象使用的这块内存不会因为这一个对象的改变而改变,但是如果每个对象都需要改变,那就回出现每个对象都有自己的数据内存,这种时候就达不到我们使用引用计数节约内存的效果了,但是毕竟是少数情况。

下面看一个实现引用计数的代码:

#include <iostream>
#include<string>
using namespace std;
//引用计数

class Dog
{	

public:
	static Dog* make(const string& name)
	{
		return new Dog(name);
	}
	Dog(const Dog&d):nm(d.nm),refcount(1)
	{
		cout<<"Dog copy() "<<*this<<endl;
	}
	~Dog()
	{
		cout<<"Deleteing Dog(): "<<*this<<endl;
	}
	void attach()//增加引用计数
	{
		++refcount;
		cout<<"Dog attach() "<<*this<<endl;
	}

	void detach()//减少引用计数
	{
		cout<<"Dog detach()"<<*this<<endl;
		if(--refcount == 0)
			delete this;
	}
  Dog* unalias()
  {
	  cout<<"Dog unalias() "<<*this<<endl;
      if(refcount == 1)
		  return this;
	  --refcount;
	  return new Dog(*this);
  }

  void rename(const string& newName)
  {
	  nm = newName;
	  cout<<"Dog rename to: "<<*this<<endl;
  }

  friend ostream&
	  operator<<(ostream& os,const Dog& d)
  {
	  return os<<"d.nm= "<<d.nm<<"rc= "<<d.refcount;
  }
private:
	int refcount;//引用计数
	string nm;
	Dog(const string& name=""):nm(name),refcount(1)
	{
		cout<<"Creating Dog: "<<*this<<endl;
	}
};
class DogHouse
{
public:
	DogHouse(Dog* dog,const string& house):p(dog),houseName(house)
	{
		cout<<"Doghous()"<<*this<<endl;
	}
	DogHouse(const DogHouse &dh):p(dh.p),houseName(dh.houseName)
	{
		p->attach();
       cout<<"Copy DogHouse: "<<*this<<endl;
	}
   DogHouse& operator=(const DogHouse& dh)
   {
	   if(&dh != this)
	   {
        p->detach();
		p=dh.p;
		p->attach();
	   }
	   cout<<"Doghouse operator=: "<<*this<<endl;
	   return *this;
   }
   ~DogHouse()
   {
	   cout<<"Doghouse destructor: "<<*this<<endl;
	   p->detach();
   }


   void renameHouse(const string& newName)
   {
	   houseName = newName;
   }
   void unalias()//保证所修改的内存中没有别的对象正在使用,如果有别的对象在使用,就建立一个新对象内存空间
   {
	 p = p->unalias();
   }
  void renameDog(const string& newName)//修改数据
  {
	  unalias();//防止修改别名后的对象的数据
	  p->rename(newName);
  }
  Dog* getDog()
  {
	  unalias();
	  return p;
  }
  friend ostream&
	  operator<<(ostream& os,const DogHouse& d)
  {
	  return os<<d.houseName<<"contains"<<*d.p;
  }
private:
	Dog* p;
	string houseName;
};
void main()
{
	DogHouse fidos(Dog::make("Fido"),"FidoHouse"),
		spots(Dog::make("spot"),"SpotHouse");
	cout<<"----copy----\n";
	DogHouse bobs(fidos);

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值