String浅拷贝、引用计数和深拷贝

1 篇文章 0 订阅

1. 浅拷贝

浅拷贝,是指原对象与拷贝对象共用一份实体,仅仅是对象名字不同而已(类似引用,即对原对象起别名),其中任何一个对象改变都会导致其他的对象也跟着它变。

#include <stdio.h>
#include <string.h>
#include <unistd.h>

//g++ -o StringSimple StringSimple.cpp

class String
{
public:
	String(const char* pStr = "")//构造函数
		:_pStr(new char[strlen(pStr)+1])
	{
		if(0 == *pStr)//字符串为空
		{
			*_pStr = '\0';
		}
		else//字符串不为空
		{
			strcpy(_pStr,pStr);
		}
	}
	String(const String& s)//拷贝构造函数
	{
		_pStr = s._pStr;
	}
	String& operator=(String& s)//赋值运算符重载
	{
		if(_pStr != s._pStr)//判断是不是自己给自己赋值
		{
			_pStr = s._pStr;
		}
		return *this;
	}
	~String()//析构函数
	{
		if(NULL == _pStr)
		{
			return;
		}
		else
		{
			delete []_pStr;
			_pStr = NULL;
		}
	}
  char* getStrPoint() {
      return _pStr;
    }
private:
	char* _pStr;

};


int main()
{
    String str1("abcdeaaaaa");
    String str2(str1);
    String str3;
    str3 = str1;

    //三个地址是一样的
    printf(" str1: %lx\n", (long)str1.getStrPoint());
    printf(" str2: %lx\n", (long)str2.getStrPoint());
    printf(" str3: %lx\n", (long)str3.getStrPoint());


    sleep(5);
    return 0;
}
图一

从上面的日志可以看出:内存被多次释放 。可以考虑通过引用计数的方式避免多次释放,只有计数器的值为0时,才可能真正释放内存。

 

2. 引用计数

通过引入计数器cnt,来解决浅拷贝多次释放同一块内存的问题。

#include <stdio.h>
#include <string.h>



class String
{

 public:
  //构造函数
  String(const char* pStr = "")
    :_pStr(new char[strlen(pStr) + 1])
    ,_cnt(new int(0))
    {
      if (0 == *pStr) {
        *_pStr = '\0';
      }
      else //字符串 不为空
      {
        strcpy(_pStr, pStr);
      }
      (*_cnt)++;
      printf("==构造函数==\n");
    }

    String(const String& s) //拷贝构造函数
    {
      _pStr = s._pStr;
      _cnt = s._cnt;
      (*_cnt)++;
      printf("==拷贝构造函数==\n");
    }

    ~String() //析构函数
    {
      if(NULL == _pStr)
      {
        return ;
      }
      else
      {
        if ((--(*_cnt)) == 0)
        {
          delete _cnt;
          delete []_pStr;
          _cnt = NULL;
          _pStr = NULL;
        }
      }
      printf("==析构函数==\n");
    }

    String& operator=(const String& s) //赋值运算符
    {
      //先释放旧数据
      if (NULL != _pStr)
      {
        if ((--(*_cnt)) == 0)
        {
          delete _cnt;
          delete []_pStr;
          _cnt = NULL;
          _pStr = NULL;
          printf("==赋值函数,释放旧内存==\n");
        }
      }
      _pStr = s._pStr;
      _cnt = s._cnt;
      (*_cnt)++;

      printf("==赋值函数==\n");
      return *this;
    }

 private:
  char* _pStr;
  int* _cnt;
};

int main()
{
    String str1("abcdeabbbb");
    String str2(str1);
    String str3;
    str3 = str1;

    return 0;
}

 

3. 深拷贝

每次拷贝都是重新申请一块内存,再把内容拷贝过去,当数据比较大时,这种方式是比较耗内存的,而且也会影响性能。

#include <stdio.h>
#include <string.h>
#include <unistd.h>


class String
{
public:
	String(const char* pStr = "")//构造函数
		:_pStr(new char[strlen(pStr)+1])
	{
		if(0 == *pStr)//字符串为空
		{
			*_pStr = '\0';
		}
		else//字符串不为空
		{
			strcpy(_pStr,pStr);
		}
	}
	String(const String& s)//拷贝构造函数
    :_pStr(new char[strlen(s._pStr)+1])
	{
    strcpy(_pStr,s._pStr);
	}

	String& operator=(const String& s)//赋值运算符重载
	{
		if(_pStr != s._pStr)//判断是不是自己给自己赋值
		{
      if (NULL != _pStr)
      {
        delete []_pStr;//释放当前对象
      }
      char* temp  = new char[strlen(s._pStr)+1];//先开辟一段新空间
			strcpy(temp,s._pStr);//将原对象的值赋给新空间
			_pStr = temp;//将当前对象指向新开辟的空间
		}
		return *this;
	}
	~String()//析构函数
	{
		if(NULL == _pStr)
		{
			return;
		}
		else
		{
			delete []_pStr;
			_pStr = NULL;
		}
	}
  char* getStrPoint() {
      return _pStr;
    }
private:
	char* _pStr;

};


int main()
{
    String str1("abcdecccc");
    String str2(str1);
    String str3;
    str3 = str1;

    //三个地址是不一样的
    printf(" str1: %lx\n", (long)str1.getStrPoint());
    printf(" str2: %lx\n", (long)str2.getStrPoint());
    printf(" str3: %lx\n", (long)str3.getStrPoint());


    return 0;
}

从运行的结果看,三个对象的地址是不一样的。

总结:

(1)浅拷贝,是指原对象与拷贝对象共用一份实体,存在内存被多次释放的问题;

(2)引用计数,引用计数的方法可以解决浅拷贝多次释放内存的问题;

(3)深拷贝,每个对象都申请自己独立的内存,各个对象间互不影响,当数据比较大时,比较耗内存,也影响性能。

 

水平有限,难免存在疏漏,欢迎指出错误,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值