现在的位置: 首页 > 综合 > 正文

《程序员面试宝典》错误题:拷贝构造函数 浅拷贝、深拷贝

2013年09月06日 ⁄ 综合 ⁄ 共 1507字 ⁄ 字号 评论关闭

#include <vector>
using namespace std;
class CDemo{
public:
CDemo():str(NULL){}
~CDemo(){if(str) delete [] str;}
char *str;
};

int main()
{
CDemo d1;
d1.str = new char[32];
strcpy(d1.str, "trend micro");

vector <CDemo> *a1 = new vector <CDemo>();
a1 -> push_back(d1);

delete a1;

return 0;
}

上述代码运行时出错。
a1 -> push_back(d1); 是在a1所指的向量的尾部插入一个CDemo对象d,d的值与d1相等(调用默认拷贝构造函数,是浅拷贝),自然d.str=d1.str,即都指向同一内存地址。delete a1会调用vector<>的析构函数~vector(),在~vector()中也一定释放了各CDemo元素的内存空间(调用每个元素的~CDemo()),这里由于vector中只有一个元素,故只调用一次~CDemo(),这使得d.str被释放一次。
接着,因为d1是个局部变量,在main函数退出后,d1析构函数~CDemo()被调用,而d1.str所指内存空间已经在前面被释放,所以会出现运行时错误。

vector的一个可能版本如下:
template< typename T>
class vector
{
public:
 vector()
 {
   m_pData= new T[ 10];
 }

 ~vector()
 {
   if ( m_pData != NULL)
     delete[] m_pData;//调用T的析构函数(调用次数为向量中元素的个数)
 }

 T* m_pData;
}

以上问题实质上是浅拷贝、深拷贝的问题。
添加拷贝构造函数,就可以解决:
CDemo(const CDemo &cd)
{
  cout < < "copy constructor:" < < endl;
  this->str = new char[strlen(cd.str)+1];
  strcpy(str, cd.str);
}

另一种参考方法:
int main()
{
CDemo d1;
d1.str = new char[32];
strcpy(d1.str, "trend micro");

    vector<CDemo*>   *a1=new   vector<CDemo*>();
    a1->push_back(&d1);

delete a1;

return 0;
}
    
那么在    “delete   a1;”时,会释放vector空间,调用~vector(),如果元素是一个类A,则调用类A的析构函数;而如果元素是指针,则不需调用析构函数,故向量中第一个元素(为CDemo*类型)此时不会被delete掉。而当局部变量d1跳出其作用域main()时,会调用d1的~CDemo(),释放d1.str所指向的32B空间。这样的结果是正确的。
--------------
而如果vector中元素是指针类型,如
vector <TestFree*> ::iterator  iterp;     //定义迭代器
 iterp   =  p_TestArray.begin();
 while (iterp   !=  p_TestArray.end())
 {
  delete   *iterp;              //先用迭代器释放空间,再用erase
  iterp=p_TestArray.erase(iterp);
 }
要先用delete释放指针申请的空间,再用erase将此指针从向量中删除(删除的过程可能是将后面的值往前移)。

 

抱歉!评论已关闭.