zoukankan      html  css  js  c++  java
  • 浅析:浅拷贝 及 深拷贝的传统写法

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

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

     1 #include <iostream>
     2 using namespace std;
     3 
     4 class String
     5 {
     6 public:
     7            String(char *str)
     8                     :_str(new char [strlen(str )+1])
     9            {
    10                               strcpy(_str, str);
    11            }
    12            String(const String & s)
    13            {
    14                     _str = s._str;
    15            }
    16            String& operator=(const String & s )
    17            {
    18                     if (this !=&s)
    19                     {
    20                               _str = s._str;
    21                     }
    22                     return *this ;
    23            }
    24            ~String()
    25            {
    26                     delete[] _str;
    27            }
    28 private:
    29            char* _str;
    30 };
    31 
    32 void Test()
    33 {
    34            String s1("Lynn" );
    35            String s2=s1;
    36 }
    37 int main()
    38 {
    39            Test();
    40            system("pause" );
    41            return 0;
    42 }
    浅拷贝

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

    深拷贝
     1 ///////////////////////////////////////////////////////////////////////////////////////
     2  
     3 //          写String类的构造函数时一定要注意参数问题
     4 //          首先要考虑到构造的对象分有参数和无参数两种情况
     5 //          构造对象的时候不能直接赋值,否则一块内存两次释放的话程序会出错
     6 //          无参的构造函数不能将_str指针赋值为NULL,因为不能strlen(NULL)
     7 //          赋值运算符的重载要考虑到有可能分配内存失败的问题
     8 //          当然,记得要给''分配空间哦
     9 //                                                                     By:Lynn-Zhang
    10 //////////////////////////*****************////////////////////////////////////////////
    11  
    12 #include<iostream>
    13 using namespace std;
    14  
    15 class String
    16 {
    17 public:
    18             
    19            String(char * str="")          //不能strlen(NULL)
    20                     :_str(new char [strlen(str ) + 1])
    21            {
    22                     strcpy(_str, str);
    23            }
    24            String(const String &s)
    25                     :_str(new char [strlen(s ._str) + 1])
    26            {
    27                     strcpy(_str, s._str);
    28            }
    29             
    30            //赋值运算符的重载
    31            String& operator=(const String& s)
    32            {
    33                     if (this != &s )
    34                     {
    35                         /*     //有可能开辟空间失败,但是却破坏了_str的内容
    36                                delete[] _str;
    37                                _str = new char[strlen(s._str) + 1];
    38                                strcpy(_str, s._str);   */
    39  
    40                               char* tmp = new char [strlen(s ._str) + 1];
    41                               strcpy(tmp, s._str);
    42                               delete[] _str;
    43                               swap(_str, tmp);
    44  
    45                     }
    46                     return *this ;
    47            }
    48            char* CStr()
    49            {
    50                     return _str;
    51            }
    52            ~String()
    53            {
    54                     delete[] _str;
    55            }
    56 private:
    57            char* _str;
    58 };
    59  
    60  
    61 //函数测试
    62 void Test()
    63 {
    64            String s1("aaaaa" );
    65            cout << s1.CStr() << endl;
    66            String s2(s1);
    67            cout << s2.CStr() << endl;
    68            String s3 = s1;
    69            s3= s2;
    70            cout << s3.CStr() << endl;
    71            String s4;
    72            // s4 = s1;
    73            cout << s4.CStr() << endl;
    74            
    75 }
    76 int main()
    77 {
    78            Test();
    79            system("pause" );
    80            return 0;
    81 }

  • 相关阅读:
    RT throttling分析【转】
    linux异步IO的两种方式【转】
    linux select 与 阻塞( blocking ) 及非阻塞 (non blocking)实现io多路复用的示例【转】
    10. linux输入子系统/input 设备【转】
    Unix/Linux进程间通信(一):概述
    Linux进程间通信(九):数据报套接字 socket()、bind()、sendto()、recvfrom()、close()
    Linux进程间通信(八):流套接字 socket()、bind()、listen()、accept()、connect()、read()、write()、close()
    PHP函数 rtrim() 的一个怪异现象
    Linux进程间通信(七):消息队列 msgget()、msgsend()、msgrcv()、msgctl()
    Linux进程间通信(六):共享内存 shmget()、shmat()、shmdt()、shmctl()
  • 原文地址:https://www.cnblogs.com/Lynn-Zhang/p/5398704.html
Copyright © 2011-2022 走看看