关于“非基本类型需慎用memcpy函数”的分析

假设我们要将一个元素类型为T的对象数组复制到另外一个数组中,我可以很轻松写出如下代码

T sour[N];
T dest[N];
int i;
for(i = 0; i < N; i++)
	dest[i] = sour[i];
在C和C++中,上述代码都可以生效

然而,C程序员可能更喜欢用下面的方案

T sour[N];
T dest[N];
int i;
memcpy(dest, sour, N*sizeof(T));
这种做法在C中能很好的工作,然而如果T是非基本类型,上述代码在C++中就有可能会带来灾难,因为memcpy是按位拷贝,这涉及到深拷贝和浅拷贝的问题


如果类型T具有下面的特征,则不能对其使用memcpy

1.类型T需要显式定义复制构造函数和赋值操作符

2.类型T不需要显式定义复制构造函数和赋值操作符,但其底层数据成员需要显式定义复制构造函数和赋值操作符

参照下列代码

#include <iostream>
#include <string>
using namespace std;
//不能对B使用memcpy函数的原因是显而易见的
class B
{
public:
	int *a;
	B(int m = 0)
	{
		cout << "B的构造函数" << endl;
		a = new int;
		*a = m;
	}
	B(const B& b)
	{
		cout << "B的复制构造函数" << endl;
		a = new int;
		*a = *(b.a);
	}
	B& operator=(const B& b)
	{
		cout << "调用B的赋值操作符" << endl; 
		if(&b != this)
		{
			delete a;
			a = new int;
			*a = *(b.a);
		}
		return *this;
	}
	~B()
	{
		cout << "调用B的析构函数" << endl;
		delete a;
	}

};
//A不需要定义复制构造函数、赋值操作符、析构操作符,但也不能对A使用mencpy函数
class A
{
public:
	B b;
	A(int m = 0) : b(m) {}
};
void main()
{ 
	A a1(1);
	A a2(2);

	cout << "测试A是否需要赋值操作符" << endl;
	cout << "a1: " << a1.b.a << " " << *(a1.b.a) << endl;
	cout << "a2: " << a2.b.a << " " << *(a2.b.a) << endl;
	a1 = a2;
	//memcpy(&a1,&a2,sizeof(A));//注意万万不可对A调用memcpy这种按位拷贝函数
	cout << "a1: " << a1.b.a << " " << *(a1.b.a) << endl;
	cout << "a2: " << a2.b.a << " " << *(a2.b.a) << endl;	
	
	cout << "测试A是否复制构造函数" << endl;
	A a3(1);
	cout << "a3: " << a3.b.a << " " << *(a3.b.a) << endl;
	A a4(a3);
	cout << "a4: " << a4.b.a << " " << *(a4.b.a) << endl;
}
运行结果

B的构造函数

B的构造函数
测试A是否需要赋值
a1: 00036208 1
a2: 00036238 2
调用B的赋值操作符
a1: 00036208 2
a2: 00036238 2
测试A是否复制构造
B的构造函数
a3: 000362E0 1
B的复制构造函数
a4: 00036310 1
调用B的析构函数
调用B的析构函数
调用B的析构函数
调用B的析构函数


注:默认的赋值操作符和复制构造函数递归的依赖于底层类的成员的复制和赋值的定义,它不仅仅像C版本的结构体那样仅实施按位复制,它只向内建类型成员变量实施按位复制,默认的析构函数也递归的依赖于底层类的析构函数

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值