别拿浅拷贝不当拷贝

我们知道C++中类里的成员函数中构造函数和拷贝构造都是值拷贝,所以地址也是值拷贝,也就是多个对象用到了同样的一块地址,例如:

#include <iostream>
using namespace std;

class String
{
public:
    String(char* str)
    :_str(new char[strlen(str)+1])
    {
        strcpy(_str,str);
    }
    //拷贝构造函数
    ~String()
    {
        delete this->_str;
    }
private:
    char* _str;
};

void Test()
{
    String s1("abcdef");
    String s2(s1);
}

int main()
{
    Test();
    return 0;
}

上面的程序中我省略掉了拷贝构造函数,系统会自动生成一个,就是值拷贝,也是浅拷贝,因此s1和s2中字符串指针指向了由new开辟出来的同一块地址,那么当出了Test()的作用域时会调用两次析构函数,那么也就是会把同一块内存释放两次,系统毫无疑问就会崩溃掉,那么解决这个问题的方法就可以用深拷贝,开辟出同样大小的一块空间,再将字符串的内容给拷贝过去。

但是,就用浅拷贝可不可以解决上述问题呢?看如下的程序:

#include <iostream>
using namespace std;
class String
{
public:
 String(char* s = "")
  :_str(new char[strlen(s)+5])
 {
  *((int*)_str) = 1;  //初始化计数器个数为1
  strcpy(_str+4,s);
 }
 String(String& str)
 {
  _str = str._str;
  ++(*((int*)_str));  //每当增加一个对象使用这块内存时计数器就++
 }
 ~String()
 {
  if((--(*((int*)_str))) == 0)//释放内存时只有当计数器减完后为0时才可以释放
  {
   delete[] _str;
  }
 }
 String& operator=(String& str)
 {
  if(--(*((int*)_str)) == 0)//只有确保没有其他对象在使用这块空间时才可以将原来的空间释放
  {
   delete[] _str;
  }
  _str = str._str;
  ++(*((int*)_str));
  return *this;
 }
private:
 char* _str;
};
void Test1()
{
 String s1("abcd");
 String s2(s1);
 String s3 = s2;
 String s4("efgh");
 String s5;
 s5 = s4;
}
int main()
{
 Test1();
 return 0;
}

在上面的程序中注意到在构造函数的初始化类表中我new出了多4个字节的空间,那这4个空间是用来干什么的呢?

在用new[ ]的时候,如果用sizeof检查其字节,会发现开辟出的大小会多出4个字节,这四个字节在开辟出的空间首部,用来存储数组元素的个数,从而配合delete来释放空间。

因此,我多开辟出的4个空间就也是用来存放指向同一块空间的对象的个数的。

这样就可以在需要重复使用相同的内容时节省内存空间也避免出现内存泄露或者程序崩溃。

时间: 2024-10-07 07:08:23

别拿浅拷贝不当拷贝的相关文章

Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)

http://www.jb51.net/article/15714.htm 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象.2. copy.deepcopy 深拷贝 拷贝对象及其子对象 一个很好的例子: 1 import copy 2 a = [1, 2, 3, 4, ['a', 'b']] #原始对象 3 4 b = a #赋值,传对象的引用 5 c = copy.copy(a) #对象拷贝,浅拷贝 6 d = copy.deepcopy(a) #对象拷贝,深拷贝

Python拷贝(深拷贝deepcopy与浅拷贝copy)

Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块. 1.copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2.copy.deepcopy 深拷贝 拷贝对象及其子对象 >>> import copy >>> a = [1,2,3,4,['a','b']] #原始对象 >>> b = a #赋值,传对象的引用 >>> c = copy.copy(a) >>&g

python(41):copy拷贝(深拷贝deepcopy与浅拷贝copy)

Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块. 1.copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2.copy.deepcopy 深拷贝 拷贝对象及其子对象 >>> import copy >>> a = [1,2,3,4,['a','b']] #原始对象 >>> b = a #赋值,传对象的引用 >>> c = copy.copy(a) >>&g

Java clone()深拷贝、浅拷贝

Cloneable接口是一个空接口,仅用于标记对象,Cloneable接口里面是没有clone()方法,的clone()方法是Object类里面的方法!默认实现是一个Native方法 protected native Object clone() throws CloneNotSupportedException; 如果对象implement Cloneable接口的话,需要覆盖clone方法(因为Object类的clone方法是protected,需要覆盖为public) public Obj

完全理解python深拷贝和浅拷贝

import copya = [1, 2, 3, 4, ['a', 'b']]  #原始对象b = a  #赋值,传对象的引用c = copy.copy(a)  #对象拷贝,浅拷贝d = copy.deepcopy(a)  #对象拷贝,深拷贝a.append(5)  #修改对象aa[4].append('c')  #修改对象a中的['a', 'b']数组对象print 'a = ', aprint 'b = ', bprint 'c = ', cprint 'd = ', d 输出结果:a = 

javaScript之深拷贝与浅拷贝

js中有两种数据类型: 1.  基本类型  :  Number.String.Boolean.Null.Undefined 2.  复杂类型  :  Object .Array 深拷贝和浅拷贝只针对复杂类型的数据,因为基本类型数据的定义都会重新开辟新的内存. 浅拷贝拷贝的是内存地址,只是增加一个指针指向已有的内存,这时多个数据共用一个内存空间:深拷贝是新增了指针并且新开辟了内存空间,新指针指向新的内存. 浅拷贝: var a={ name:'WangJing', sex:'女', age:'25

python中的浅拷贝和深拷贝

1.浅拷贝 copy.copy() 浅拷贝是拷贝只拷贝最外一层(这里所说的拷贝是重新生成一个内存地址,也就是只有最外层的地址是重新生成) import copy li=[23,45,['wew',35,[33,00]]] li1=copy.copy(li) print(id(li),id(li1)) print(id(li[0]),id(li1[0])) print(id(li[2][1]),id(li1[2][1])) #输出:35540704 5872576 # 1625084720 162

深浅拷贝与赋值

参考:http://www.cnblogs.com/Eva-J/p/5534037.html 对于 数字 和 字符串 而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址.(可以把数字,字符串看作是内存中最小的地址) 对于字典.元祖.列表 而言,进行赋值.浅拷贝和深拷贝时,其内存地址的变化是不同的.浅拷贝只拷贝第一层地址,而深拷贝是不管你数据结构多么复杂,都在内存里开辟一块新的空间,直到简单数据类型为止. 以这个字典为例: dict = {"k1":"mu"

深浅拷贝 python

原文:http://www.jb51.net/article/15714.htm 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象.2. copy.deepcopy 深拷贝 拷贝对象及其子对象一个很好的例子: import copya = [1, 2, 3, 4, ['a', 'b']]  #原始对象b = a  #赋值,传对象的引用c = copy.copy(a)  #对象拷贝,浅拷贝d = copy.deepcopy(a)  #对象拷贝,深拷贝a.append(5)