C++拷贝构造、赋值构造详解

一、前言

写一个用到指针的程序时,被拷贝、赋值、析构函数坑了一波,网上查相关博客,发现关于拷贝、赋值构造函数调用时机大多都有错误,因此决定自己总结撸一发博客。

A (A& a);                       //拷贝构造函数
A (const A& a);                 //拷贝构造函数
A& operator= (const A& a);      //赋值构造函数

先写一个类,用作之后的示例

class A {
public:
    int* x;
    int y;
    A() = default;
    A (const A& a) {
        printf ("拷贝构造\n");
        this->x = a.x;
        this->y = a.y;
    }

    A& operator= (const A& a) {
        printf ("赋值构造\n");
        this->x = a.x;
        this->y = a.y;
    }
    A (int t) {
        x = new int (0);
        y = t;
        printf ("address: %x, point: %x, value: %d\n", this, x, y);
    }
    ~A() {
        printf ("delete %x\n", this);
    }
};

A f () {
    A ret (3);
    printf ("stack address: %x, point: %x, value: %d\n", &ret, ret.x, ret.y);
    return ret;
}

二、不会调用拷贝构造函数和赋值构造函数的情况

1.当对象以值传递的方式从函数返回,且接受返回值的对象是由该返回值初始化时,不会调用任何构造函数。(相当于把该对象重命名为另一个对象名)

int main() {
    A c = f();         //此时不调用任何构造函数
    printf ("global address: %x ,value: %d\n", &c, c.y);
    return 0;
}

这里写图片描述

三、拷贝构造函数

1.对象需要通过另外一个对象进行初始化

int main() {
    A a(1);
    A c = a;
    printf ("global address: %x, point: %x, value: %d\n", &c, c.x, c.y);
    return 0;
}

这里写图片描述
2.对象通过值传递方式进入函数

void g (A ret) {
    printf ("stack address: %x, point: %x, value: %d\n", &ret, ret.x, ret.y);
}

int main() {
    A a (1);
    g (a);
    return 0;
}

这里写图片描述

四、赋值构造函数

1.对象以值传递方式从函数返回,且接受返回值的对象已经初始化过

int main() {
    A c;
    c = f();
    printf ("global address: %x, point: %x, value: %d\n", &c, c.x, c.y);
    return 0;
}

这里写图片描述
2.对象直接赋值给另一个对象,且接受值的对象已经初始化过

int main() {
    A a(1);
    A c;
    c = a;
    printf ("global address: %x, point: %x, value: %d\n", &c, c.x, c.y);
    return 0;
}

这里写图片描述

五、总结

对象以值传递方式从函数返回时,若接受返回值的对象已经初始化过,则会调用赋值构造函数,且该对象还会调用析构函数,当对象中包含指针时,会使该指针失效,因此需要重载赋值构造函数,使用类似深拷贝或移动构造函数的方法赋值,才能避免指针失效。
对象以值传递方式从函数返回时,若接受返回值的对象是由该返回值初始化,则不会调用任何构造函数,且不会调用析构函数

猜你喜欢

转载自blog.csdn.net/qq_31759205/article/details/80544468
今日推荐