首页 > 应用开发 > > C++中位拷贝与值拷贝的区别
位拷贝拷贝的是地址(也加浅拷贝),而值拷贝则拷贝的是内容(深拷贝)。深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。
位拷贝,即“bitwise assignment”是指将一个对象的内存映像按位原封不动复制给另一个对象;所谓值拷贝就是指将原对象的值复制一份给新对象。在用“bitwise assignment”时会直接将对象的内存映像复制给另一个对象,这样两个对象会指向同一个内存区域,当一个对象被释放后,另一个对象的指针会成为野指针(悬挂指针)。这时,就应该编写operator和copy constructor来实现值拷贝。
默认的拷贝构造函数和缺省的赋值函数均采用“位拷贝”而非值拷贝的方式来实现,一旦含有指针变量,这两个函数注定将出错。
当用一个已初始化过了的自定义类类型对象去初始化另一个新构造对象的时候,拷贝构造函数就会自动被调用。也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用,下面情况都会调用拷贝构造函数:
①一个对象以值传递的方式传入函数体
②一个对象以值传递的方式从函数返回
③一个对象需要通过另外一个对象进行初始化
如果类中没有显示地表明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝。自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。
如果没有自定义复制构造函数,则系统会创建默认的复制构造函数,但系统创建的默认复制构造函数只会执行“位拷贝”,即将被拷贝对象的数据成员值赋值给新创建的对象,若该类的数据成员中有指针成员,则会使得新的对象的指针所指向的地址与被拷贝对象的指针所指向的地址相同,delete该指针时会导致重复delete而出错。
下面看一下我们经常使用的String经典示例:
ClassString{
public:
String(constchar*ch=NULL);//默认构造函数
String(constString&str);//拷贝构造函数
~String(void);
String&operator=(constString&str);//赋值函数
private:
char*m_data;
};
以String为例定义strA和strB
intmain()
{
StringstrA("hello");
StringstrB("world");
strB=strA;
// 结果导致 strA 和 strB 的指针都指向了同一个地址
// 函数结束析构时
// 同一个地址被delete两次
return 0;
}
如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。一旦类中含有指针变量,那么这两个缺省的函数就隐含了错误。以类String的两个对象strA和strB为例,假设strA.m_data的内容为“hello”,strB.m_data的内容为“world”。现将strA赋给strB,缺省赋值函数的“位拷贝”意味着执行strB.m_data =strA.m_data。那么这将造成三个错误:
①strB.m_data原有的内存没被释放,造成内存泄漏
②strB.m_data和strA.m_data指向同一块内存,strA或strB任何一方变动都会影响另一方
③在对象被析构时,m_data被释放了两次
对应编译器,如果不主动编写拷贝函数和赋值函数,它会以位拷贝的方式自动生成缺省的函数。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/1978/viewspace-3149577/ ,如需转载,请注明出处,否则将追究法律责任。