程序员面试宝典-第九章-面试例题2-深浅复制

本文探讨了一段C++代码中存在的深拷贝问题。该问题源于类成员中包含指向字符串的指针,而在使用默认拷贝构造函数时导致浅拷贝现象。文章详细解析了错误原因,并给出了正确的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include "stdafx.h"
#include <iostream>
#include <vector>

using namespace std;

class Demo
{
public:
	Demo(const char* a)
	{
		str = new char[32];
		strcpy(str,a);
	}

	~Demo()
	{
		if (str)
			delete [] str;
	}
private:
	char *str;
};

int _tmain(int argc, _TCHAR* argv[])
{
	Demo d("Hello,World!");
	vector<Demo> *p = new vector<Demo>();
	p->push_back(d);
	delete p;
	return 0;
}

问:这段代码有错误,请找出其中出错的原因。

      代码自己定义了一个类,类中有一个变量,有构造函数,析构函数。在主函数中,实例化一个Demo类型的变量d,用Vector存放这个变量d,最后删除vector。执行这段代码之后,程序会出错,无法执行下去。

      要明白这个程序,得先了解当执行vector的push_back(d)函数时,加入到vector中的是原来的d对象呢,还是d对象的副本?

      答案是d对象的副本,当vector中添加元素的时候,是将元素值复制到容器里。就是说容器中存放的是原始元素的副本。被复制的原始值与新容器中的元素各不相关,此后,容器内元素值发生变化时,被复制的原值不会受到影响。

      既然加入到vector中的对象是副本,那么就涉及到d对象的复制,程序中并没有写复制构造函数,但是类会调用默认的复制构造函数(或者称为合成复制构造函数),默认构造函数只是简单的将对象的每个非static成员,依次复制到正创建的对象。Demo类只有一个成员变量char * str,这是一个指针类型的变量,因此会执行this.str = d.str;其结果是两个指针共同指向了同一块儿内存区域。(这就是所谓的浅层复制,不清楚的可以看看)

      因为当执行delete p;时,在销毁vector对象的同时,也会将vector中存储的对象同时销毁掉,d的副本str指向的区域被销毁掉,此时d的str成员就成了悬垂指针。当main执行完毕后,需要将d销毁掉,此时d的str成员是悬垂指针,因此会找不到要销毁的内容,程序就会出错。

     这个问题实质上的问题在于,类的深层复制和浅层复制的区别。当有指针类型成员变量的时,应该采取深层复制。当执行复制操作时,保证每个对象都有自己的独立的内存空间。

程序应该修改如下:

#include "stdafx.h"
#include <iostream>
#include <vector>

using namespace std;

class Demo
{
public:
	Demo(const char* a)
	{
		str = new char[32];
		strcpy(str,a);
	}

	Demo(const Demo& d)
	{
		this->str = new char[32];
		strcpy(str,d.str);
	}
	

	~Demo()
	{
		if (str)
			delete [] str;
	}
private:
	char *str;
};

int _tmain(int argc, _TCHAR* argv[])
{
	Demo d("Hello,World!");
	vector<Demo> *p = new vector<Demo>();
	p->push_back(d);
	delete p;
	return 0;
}

总结:

1. 为了管理具有指针成员的类,必须自己定义三个复制控制成员:复制构造函数,复制操作符,析

    构函数。

2. vector中添加元素的时候,是将元素值复制到容器里。就是说容器中存放的是原始元素的副本。被

    复制的原始值与新容器中的元素各不相关,此后,容器内元素值发生变化时,被复制的原值不会

    受到影响,反之亦然。

3. 当删除vector对象时,会将vector中存储的对象一并删除掉。  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值