浅析:浅拷贝 及 深拷贝的传统写法

浅拷贝会造成指针悬挂的问题。

举个例子:两个对象是s1和s2的指针_str都指向new开辟的同一块空间,如下图,主程序结束时,对象逐个撤销,先撤销对象s2,会调用析构函数释放动态分配的内存;再撤销对象s1时,s1._str所指向的内存空间已经是无法访问了,而s2._str原先指向的那块内存却无法释放,出现了所谓的指针悬挂! 两个对象企图释放同一块内存,从而导致一块内存被释放两次这也是不行的,运行会出错。

浅析:浅拷贝 及 深拷贝的传统写法

浅析:浅拷贝 及 深拷贝的传统写法

#include <iostream>
using namespace std;

class String
{
public:
          String(char *str)
                    :_str(new char [strlen(str )+1])
          {
                              strcpy(_str, str);
          }
          String(const String & s)
          {
                    _str = s._str;
          }
          String& operator=(const String & s )
          {
                    if (this !=&s)
                    {
                              _str = s._str;
                    }
                    return *this ;
          }
          ~String()
          {
                    delete[] _str;
          }
private:
          char* _str;
};

void Test()
{
          String s1("Lynn" );
          String s2=s1;
}
int main()
{
          Test();
          system("pause" );
          return 0;
}

深拷贝  深拷贝解决了指针悬挂的问题,当调用拷贝构造或赋值运算符的重载函数时,程序会生成一份该内存的拷贝,这样每个指针都会指向一块相对独立的空间,撤销对象时调用析构函数,分别释放他们自己的动态分配的内存,相互之间不影响。如下图:

浅析:浅拷贝 及 深拷贝的传统写法

浅析:浅拷贝 及 深拷贝的传统写法

深拷贝
///////////////////////////////////////////////////////////////////////////////////////
 
//          写String类的构造函数时一定要注意参数问题
//          首先要考虑到构造的对象分有参数和无参数两种情况
//          构造对象的时候不能直接赋值,否则一块内存两次释放的话程序会出错
//          无参的构造函数不能将_str指针赋值为NULL,因为不能strlen(NULL)
//          赋值运算符的重载要考虑到有可能分配内存失败的问题
//          当然,记得要给'\0'分配空间哦
//                                                                    By:Lynn-Zhang
//////////////////////////*****************////////////////////////////////////////////
 
#include<iostream>
using namespace std;
 
class String
{
public:
           
          String(char * str="")          //不能strlen(NULL)
                    :_str(new char [strlen(str ) + 1])
          {
                    strcpy(_str, str);
          }
          String(const String &s)
                    :_str(new char [strlen(s ._str) + 1])
          {
                    strcpy(_str, s._str);
          }
           
          //赋值运算符的重载
          String& operator=(const String& s)
          {
                    if (this != &s )
                    {
                        /*    //有可能开辟空间失败,但是却破坏了_str的内容
                              delete[] _str;
                              _str = new char[strlen(s._str) + 1];
                              strcpy(_str, s._str);  */
 
                              char* tmp = new char [strlen(s ._str) + 1];
                              strcpy(tmp, s._str);
                              delete[] _str;
                              swap(_str, tmp);
 
                    }
                    return *this ;
          }
          char* CStr()
          {
                    return _str;
          }
          ~String()
          {
                    delete[] _str;
          }
private:
          char* _str;
};
 
 
//函数测试
void Test()
{
          String s1("aaaaa" );
          cout << s1.CStr() << endl;
          String s2(s1);
          cout << s2.CStr() << endl;
          String s3 = s1;
          s3= s2;
          cout << s3.CStr() << endl;
          String s4;
          // s4 = s1;
          cout << s4.CStr() << endl;
         
}
int main()
{
          Test();
          system("pause" );
          return 0;
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/d2e171e7c979f60bd8139581966505e2.html