• 为含指针变量的类声明一个拷贝构造函数和一个赋值操作符


    C++编译器会为每个类自动生成一个默认的构造函数、析构函数、赋值函数、拷贝构造函数,这当然是在你没有为你的类声明这些函数的时候。这些默认的功能函数在为你提供方便的时候,也会给你带来麻烦。
    
    例如:
    
    class string {
    public:
      string(const char *value);
      ~string(); 
    
      ...                           // 没有拷贝构造函数和operator= 
    
    private:
      char *data;
    }; 
    
    string::string(const char *value)
    {
      if (value) {
        data = new char[strlen(value) + 1];
        strcpy(data, value);
      }
      else {
        data = new char[1];
        *data = '\0';
      }
    } 
    
    inline string::~string() { delete [] data; }           //注意:new 和delete 要采用相同的形式。 
    
    如果有string的两个对象, 
    
    string a("hello");
    string b("world"); 
    
    当b=a时,因为你自己没为类定义那些函数,所以C++编译器会提供默认的赋值函数,这个缺省的赋值操作符会执行从a的成员到b的成员的逐个成员的赋值操作,对指针(a.data和b.data) 来说就是逐位拷贝。这种情况下至少有两个问题。 
    
    第一,b曾指向的内存永远不会被删除,因而会永远丢失。这是产生内存泄漏的典型例子。 
    
    第二,现在a和b包含的指针指向同一个字符串,那么只要其中一个离开了它的生存空间,其析构函数就会删除掉另一个指针还指向的那块内存,重复析构的问题。 
    
    下面的语句: 
    
    string a("hello");                // 定义并构造 a 
    
    {                                        // 开一个新的生存空间
      string b("world");            // 定义并构造 b 
    
      ... 
    
      b = a;                              // 执行 operator=,    调用默认赋值函数
                                             // 丢失b的内存,造成内存泄露。 
    
    }                                        // 离开生存空间, 调用 
                                             // b的析构函数 
    
    string c = a;                       // c.data 的值不能确定!  调用默认的拷贝构造函数  
                                             // 但是a.data 已被删除,无法进行拷贝构造。 
    
      
    
    当这类对象进行函数参数按值传递时,形参会按照缺省的拷贝构造函数进行初始化,形参拥有一个指向该对象指针的一个拷贝,当函数结束时,形参会调用析构函数,该对象的指针也被销毁。
    
    class stack
    {
    public:
        stack(const char *value);
        ~stack();
        char * data;
    };
    
    stack::stack(const char *value)
    {
        if(value)
        {
            data= new char[strlen(value)+1];
            strcpy(data,value);
        }
        else
        {
            data= new char[1];
            *data = '\0';
        }
    
    }
    
    inline stack::~stack()
    {
        delete []data;
    }
    
    void dosth(stack pstk)
    {
        cout<<pstk.data<<endl;
    }
    
    int main()
    {
     stack str("iamxczhang");
    
      dosth(str);
    
    }
    在析构函数出设立断点,你会看到析构函数执行两次! 
    
    
    牢记:只要类里有指针变量就得自己写拷贝构造函数和赋值函数,但是你确定用不着这些函数时,可以把这些函数做private声明而不去实现它,这就防止了会有人去调用它们,也防止了编译器去生成它们。 
    vinson
  • 相关阅读:
    Linux中python更换pip源
    Centos7安装yarn
    协方差矩阵
    详解UML中的6大关系(关联、依赖、聚合、组合、泛化、实现)
    c# XML和实体类之间相互转换(序列化和反序列化)(转)
    C++函数传递类对象和类对象的引用
    C++三种继承方式
    1200. 最小绝对差(排序)
    1218. 最长定差子序列(动态规划)
    1009_Product of Polynomials (25分)[模拟]
  • 原文地址:https://www.cnblogs.com/vinsonLu/p/2706098.html
Copyright © 2020-2023  润新知