拷贝控制函数

来源:互联网 发布:dos命令执行java程序 编辑:程序博客网 时间:2024/05/21 00:20

        拷贝控制包括控制对象的拷贝、移动、赋值和销毁。类通过定义五种特殊的成员函数来控制这些操作,包括:拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符和析构函数。本节主要介绍拷贝构造函数、拷贝赋值运算符和析构函数。

        1. 直接初始化与拷贝初始化

什么是直接初始化,而什么又是拷贝初始化呢?

简单点来说,就是定义对象时的写法不一样,一个用括号,如ClassTest ct1("ab"),而一个用等号,如ClassTest ct2 = "ab"。但是从本质来说,它们却有本质的不同:直接初始化直接调用与实参匹配的构造函数,拷贝初始化总是调用拷贝构造函数。拷贝初始化首先使用指定构造函数创建一个临时对象,然后用拷贝构造函数将那个临时对象复制到正在创建的对象。所以当拷贝构造函数被声明为私有时,所有的拷贝初始化都不能使用。

        2. 拷贝构造函数

        如果一个函数第一个参数是自身类型的引用(通常为const引用),且任何额外的参数都有默认值,则为拷贝构造函数。

        拷贝构造函数通常用于拷贝初始化,拷贝初始化不仅在我们用=定义变量时会发生,下列情况下也会发生:

        a.将一个对象作为实参传递给一个非引用类型的形参;

        b.从一个返回类型为非引用类型的函数返回一个对象;

        c.用花括号列表初始化一个数组中的元素或一个聚合类中的成员。

        拷贝初始化用来初始化非引用类型的形参,这也决定了拷贝构造函数的参数必须是引用类型。如果其参数不是引用类型,则调用永远不会成功----为调用拷贝构造函数,我们必须拷贝它的实参,而为了拷贝实参,我们又需要调用拷贝构造函数......

        有些编译器可能会对拷贝初始化的过程进行优化,将ClassTest ct2 = "ab" 优化为ClassTest ct1("ab"),但即使编译器略过了拷贝构造函数,该函数也必须是存在且可以访问的(可参考http://blog.csdn.net/ljianhui/article/details/9245661)。

3.拷贝赋值运算符

拷贝赋值运算符接受一个与其所在类相同类型的参数,并返回一个指向其左侧运算对象的引用(为保证连续赋值)。

如果你定义一个空类,编译器会默认为它声明一个默认构造函数,一个拷贝构造函数,一个拷贝赋值运算符和一个析构函数,所有这些函数都是public而且inline的。

拷贝构造运算符通常组合了析构函数和构造函数的操作。类似析构函数,赋值操作会销毁左侧对象的资源,类似拷贝构造函数,赋值操作会从右侧运算对象拷贝数据。

但两项操作必须是以正确的顺序执行的,即可以处理自赋值的情况。一个好的方法是先将右侧对象拷贝到局部变量,然后销毁左侧对象,再将数据从临时对象拷贝到左侧变

量。

4.析构函数

析构函数执行与构造函数相反的操作,即释放对象使用的资源,并销毁对象的非static数据成员。

和构造函数不同,在一个构造函数中,成员初始化在函数体执行之前完成,且按照它们在类中出现的顺序进行初始化。在一个析构函数中,首先执行函数体,然后销毁成员,

成员按照初始化顺序的逆序销毁。

通常,析构函数体用来释放对象在生存期分配的所有资源,销毁类类型的成员需要执行成员自己的析构函数。

5.三/五法则

a.需要析构函数的类也需要拷贝和赋值操作

合成的析构函数不会delete一个指针数据成员,因此我们需要自己定义析构函数释放构造函数分配的内存。

若我们为类定义了析构函数,并在析构函数中释放内存,而使用默认版本的拷贝构造函数和赋值运算符就可能发生错误。默认拷贝构造函数和赋值运算符会拷贝指针的值,

则两个对象成员指向相同的地址,在一个对象被销毁后,该指针失效,则第二个对象销毁时会delete一个无效的指针。

b.需要拷贝操作的类也需要赋值操作,反之亦然

原创粉丝点击