在线咨询
有事点这里
有事点这里
看不懂这篇文章?联系我们
("麦洛克菲"长期致力于内核安全的推广与普及,我们更专业!)
求职QQ群:223902435。讨论各种求职笔试面试问题
作者:admin 时间:2015-10-31
标题:构造函数,赋值函数注意事项

在构造函数中,如果含有动态内存分配(即用malloc()或者new分配的内存),那么必须声明自己的实现(重新分配一个内存,将被拷贝内存中的数据拷贝过来),不可采用默认的构造函数(默认的是实现位拷贝,机械的将拷贝对象中的指针指向被拷贝对象的内存)。假如不实现自己的拷贝函数,那么在传值调用的时候,它会产生问题。看看下面的例子:

 

void DoNothing(String localstring)

{

}

 

String s = "Hello, my house!";

 

DoNothing(s);

 

上面的代码看起来好象没有问题,但假如String类没有自己实现构造函数,那么就会出问题。因为被传递的参数localstring是一个值传递,如下图所示,它必须从s通过(缺省)拷贝构造函数进行初始化。由于String类没有自己实现一个拷贝构造函数,默认的拷贝构造函数将被调用。于是localstring拥有了一个s内的指针的拷贝(即localstring这个拷贝对象同样指向了s的内存部分)。当DoNothing()结束运行时,localstring离开了其生存空间,调用析构函数。其结果也将是:s包含一个指向localstring早已删除的内存的指针。

                                                                  图 默认拷贝构造函数指针复制

顺便指出,用delete去删除一个已经被删除的指针,其结果是不可预测的。所以即使s永远也没被使用,当它离开其生存空间时也会带来问题。

 

String类的C++实现是一个C++面向对象的典型例子。在很多名企面试中,这个类的实现是经常考到的。那么,它的具体实现是如何的呢?其中的构造函数和赋值函数的实现就是自己实现了内存的分配。

 

下面就来看看String类是如何实现的:

 

//String类的声明

class String

{

public:

     String(const char *str = NULL); 

     String(const String &other);

     ~ String(void);   

     //注意赋值操作符返回的是对象的引用

     String & operate =(const String &other);

private:

     char  *m_data;

};

//String类的析构函数,由于不涉及继承关系,所以没用virtual

String::~String(void)

{

     delete [] m_data;                      

}

//String的构造函数        

String::String(const char *str)

{

     //字符串为空

     if(str==NULL)

     {

         m_data = new char[1];

         *m_data = ‘\0’;                     

     }

     else

     {

         int length = strlen(str);          

         m_data = new char[length+1];

          strcpy(m_data, str);               

     }

}

//拷贝构造函数

String::String(const String &other)

{   

     int length = strlen(other.m_data);  

     m_data = new char[length+1];   

     strcpy(m_data, other.m_data);        

}

//赋值运算符

String & String::operate =(const String &other)

{   

     //防止自我赋值

     if(this == &other)

         return *this;

     //释放原来的内存

     delete [] m_data;

     //分配新内存,拷贝数据

     int length = strlen(other.m_data);  

     m_data = new char[length+1];

     strcpy(m_data, other.m_data);

     return *this;

}