拷贝构造函数、拷贝运算符、析构函数

拷贝构造函数、拷贝运算符、析构函数

定义行为像值的类

class HasPtr{
    public:
        HasPtr(const string &s = string()):ps(new string(s)), i(0) {
            cout<<"HasPtr(const string &s = string())"<<endl;
        }
        HasPtr(const HasPtr &hp) :ps(new string(*hp.ps)), i(hp.i) {
            cout<<"HasPtr(const HasPtr &hp)"<<endl;
        }
        HasPtr &operator=(const HasPtr &hp) {
            auto tmp = new string(*hp.ps); // 右侧对象拷贝到临时变量,考虑自己拷贝自己的情况。
       delete ps; // 析构左侧对象
       ps = tmp; i
= hp.i; cout<<"HasPtr &operator="<<endl; return *this; } HasPtr testCopy(HasPtr hp) { return hp; } HasPtr &testCopy1(HasPtr &hp) { return hp; } ~HasPtr() { cout<<"~HasPtr()"<<endl; } void print() { cout<<*ps<<endl; } void setPs(const string &str) { *ps = str; } private: string *ps; int i; };

调试代码

HasPtr hp("hello");                // 调用构造函数,输出HasPtr(const string &s = string())
HasPtr hp1 = hp;                   // 调用拷贝构造函数,输出HasPtr(const HasPtr &hp)
HasPtr hp2;                        // 调用构造函数,输出HasPtr(const string &s = string())
hp2 = hp;                          // 调用拷贝运算符函数,输出HasPtr &operator=
hp1.setPs("word");                 // 构造函数、拷贝构造函数、拷贝赋值运算符函数都为ps分配了新空间
hp.print();                        // 所以hp、hp1、hp2的ps指针指向的空间不一样,修改一个的值其他的不变。
hp1.print();                       // 输出word,由setPs函数修改
hp2.print();                       // 输出hello,值从hp拷贝过来,空间是新分配的。
// 实参初始化形参要调用一次拷贝构造函数,形参初始化返回的临时变量也要调用一次拷贝构造函数,
hp.testCopy(hp1);                  // 形参和临时变量在函数结束时时要销毁,调用两次析构函数。
hp.testCopy1(hp1);                 // 都是引用初始化,不需要调用拷贝构造函数。
HasPtr *hp_ptr = new HasPtr;       // 调用构造函数
vector<HasPtr> vec;                // 调用vector的默认构造函数。
vec.push_back(hp);                 // 调用拷贝构造函数

// 接下来要销毁hp,hp1,hp2和vector中的HasPtr的元素,要调用4次析构函数,但是hp_ptr指向的空间不会被销毁。

定义行为像指针的类

class HasPtr{
    public:
        // 构造函数,为指针指向分配空间(整个类也只在这个地方分配空间),use初始化为1
        HasPtr(const string &s = string()):ps(new string(s)), i(0) ,use(new size_t(1)){ 
            cout<<"HasPtr(const string &s = string())-->use"<<*use<<endl;
        }
        
        // 拷贝构造函数,只拷贝指针,use值递增
        HasPtr(const HasPtr &hp) :ps(new string(*hp.ps)), i(hp.i) ,use(hp.use){         
            ++*use;
            cout<<"HasPtr(const HasPtr &hp)-->use"<<*use<<endl;
        }
        
        // 拷贝赋值运算符,左侧use递减,当use为0,释放左侧指针指向空间,拷贝右侧数据和指针到左侧对象,use递增。
        HasPtr &operator=(const HasPtr &hp) {
            if(--*use == 0) {
                delete ps;
                delete use;
            }
            ++*hp.use;
            ps = hp.ps;
            use = hp.use;
            i = hp.i;
            cout<<"HasPtr &operator=-->use"<<*use<<endl;
            return *this;
        }
        
        HasPtr testCopy(HasPtr hp) {
            return hp;
        }
        
        HasPtr &testCopy1(HasPtr &hp) {
            return hp;
        }
        
        // 析构函数,递减use,当use为0,释放指针指向空间。
        ~HasPtr() {
            if(--*use == 0){
                delete ps;
                delete use;
            }
            cout<<"~HasPtr()-->use"<<*use<<endl;
        }
        
        void print() {
            cout<<*ps<<endl;
        }
        
        void setPs(const string &str) {
            *ps = str;
        }
        
    private:
        string *ps;    // 共享,只有构造函数分配,最后一次析构函数销毁
        int i;         // 每个对象独享,每次构造函数、拷贝构造函数、拷贝运算符都分配,每次析构都销毁
        size_t *use;   // 共享,只有构造函数分配,最后一次析构函数销毁
};

测试程序

HasPtr hp("hello");                // 调用构造函数,输出HasPtr(const string &s = string())
HasPtr hp1 = hp;                   // 调用拷贝构造函数,输出HasPtr(const HasPtr &hp)
HasPtr hp2;                        // 调用构造函数,输出HasPtr(const string &s = string())
hp2 = hp;                          // 调用拷贝运算符函数,输出HasPtr &operator=
hp1.setPs("word");                 // 拷贝构造函数、拷贝赋值运算符不为指针ps和use分配新空间
hp.print();                        // 所以hp、hp1、hp2的ps指针指向相同的空间,修改一个的值其他的也变。
hp1.print();                       // 输出word,由setPs函数修改
hp2.print();                       // 输出word,由setPs函数修改
// 实参初始化形参要调用一次拷贝构造函数,形参初始化返回的临时变量也要调用一次拷贝构造函数,
hp.testCopy(hp1);                  // 形参和临时变量在函数结束时时要销毁,调用两次析构函数。
hp.testCopy1(hp1);                 // 都是引用初始化,不需要调用拷贝构造函数。
HasPtr *hp_ptr = new HasPtr;       // 调用构造函数
vector<HasPtr> vec;                // 调用vector的默认构造函数。
vec.push_back(hp);                 // 调用拷贝构造函数

// 接下来要销毁hp,hp1,hp2和vector中的HasPtr的元素,要调用4次析构函数,只有最后一次调用析构函数才会释放ps和use指向的空间。
// 但是hp_ptr指向的空间不会被销毁。

猜你喜欢

转载自www.cnblogs.com/yuandonghua/p/11478092.html