C++学习笔记----拷贝控制(拷贝构造、拷贝赋值、析构函数)

本文介绍了C++中合成拷贝构造函数、拷贝赋值运算符和自定义析构函数的概念及作用。当类包含动态内存或引用时,自定义这些函数以避免内存问题至关重要。同时,通过=default和=delete可以显式地启用或禁用编译器的默认实现,防止不必要的拷贝和赋值操作。示例代码展示了如何正确处理对象的深拷贝和防止错误的内存释放。
摘要由CSDN通过智能技术生成

1.合成拷贝成员

在我们的自定义的类中,如果我们没有自定义拷贝构造函数、拷贝赋值函数、以及析构函数,编译器将会为我们自动合成上述函数。

class copy_test
{
public:
    void set(int val)
    {
        test = val;
    }

    void show()
    {
        cout << test << endl;
    }
private:
    int test;
};

int main()
{
    copy_test c1;
    c1.set(1);//c1的test设置为1
    copy_test c2(c1);//调用合成的拷贝构造函数
    copy_test c3 = c1;//调用合成的拷贝赋值函数
    
    c1.show();
    c2.show();
    c3.show();
}

上述输出结果均为1,说明编译器去确实为我们生成了合成的拷贝构造和拷贝赋值运算符。但是对于编译器自己合成的拷贝构造函数和拷贝赋值运算符,编译器仅仅是采用简单的赋值方式拷贝,如上的例子的合成拷贝构造函数可能是这样的:

copy_test::copy_test(const copy_test &c1)
{
	test=c1.test;
}

2.自定义析构函数

析构函数会在对象即将被销毁的时候进行调用,自定义的析构函数一般用于将函数函数内置的动态内存空间进行释放。
但是对于编译器合成的拷贝控制成员,可能会存在一些问题,如果类中的某个成员为指向动态数据类型的指针或者是一个引用时,当进行拷贝时,仅仅是通过指针的简单赋值,那么就会出现多个对象的内置指针指向同一片内存区域。当调用自定义的析构函数进行内存释放时可能会出现执行同一内存的指针被多次释放,这显然是不合法的。
所以当一个类使用的是自定义的析构函数时,毫无疑问这个类应该使用自定义的拷贝构造函数和拷贝赋值运算符

上述案例可以按照如下所示改编:

class copy_test
{
public:
    copy_test(int *p)
    {
        test = p;
    }
    copy_test(const copy_test &c)
    {
        test = new int(*(c.test));
    }
    copy_test& operator=(const copy_test &c)
    {
        test = new int(*(c.test));
        return *this;
    }
    void show()
    {
        cout << *test << endl;
    }
    ~copy_test()
    {
         delete test;
    }
private:
    int *test;
};

int main()
{
    copy_test c1(new int(10));
    copy_test c2(c1);
    copy_test c3 = c1;
    c1.show();
    c2.show();
    c3.show();
}

一个类的析构函数和赋值构造函数往往是成对出现的。

3.=default和=delete

如果我们希望编译器为我们显示的生成合成拷贝控制成员,我们可以使用 =default 来进行显示说明。
在这里插入图片描述我们只能对具有合成版本的成员函数使用=default即默认构造函数、拷贝构造函数、赋值运算符重载、析构函数。

有时候我们希望能够阻止类的拷贝和赋值,如我们的IO类不允许赋值和拷贝,我们通过使用=delete来防止函数进行拷贝和赋值。

lass test
{
public:
    test() = default;//使用默认构造函数
    test(const test& t) = delete;//不使用拷贝构造函数
    test& operator = (const test &t) = delete;//不使用合成赋值运算符
    ~test() = default;//使用合成的析构函数
};

=delete的使用应该具有以下规则:如果有一个类的数据成员不能默认构造、拷贝、复制或销毁,则相应的成员函数将会被定义为删除的。

  • 析构函数不能是删除的成员,否则对象将无法销毁。
  • 一个成员有删除的或者不可访问的析构函数则会导致合成的默认和拷贝构造函数被定义为删除的。
  • 具有引用或者const成员的类具有删除的合成拷贝构造和合成复制函数,对一个const的成员复制是不允许的,对引用的复制,依然是同一个变量的引用,这没有太大意义。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值