晋州做网站,可以做游戏的网站有哪些方面,wordpress 插件 标题,wordpress更改1.拷贝、值与销毁#xff1a;
拷贝构造函数#xff1a;如果一个构造函数的第一个参数是自身类类型的引用#xff0c;且其他#xff08;如果有的话#xff09;参数都有默认实参#xff0c;则此构造函数叫做拷贝构造函数#xff1b;如果我们没有为类定义一个拷贝构造函数…
1.拷贝、值与销毁
拷贝构造函数如果一个构造函数的第一个参数是自身类类型的引用且其他如果有的话参数都有默认实参则此构造函数叫做拷贝构造函数如果我们没有为类定义一个拷贝构造函数那么编译器就会为我们定义一个合成拷贝构造函数。
拷贝初始化
直接初始化与拷贝初始化的差异当使用直接初始化时我们实际上是要求编译器使用普通的函数匹配来选择与我们提供的参数最匹配的构造函数。当我们使用拷贝初始化时我们要求编译器将右侧运算对象拷贝到正在创建的对象中而不是直接将值赋予正在创建的对象是先构造一个临时对象然后将其拷贝到正在创建的对象如果需要的话还要进行类型转换。
拷贝初始化不仅在我们用 “ ”定义变量时会发生在下列情况中也会发生 1将一个对象作为实参传递给一个非引用类型的形参 2从一个返回类型为非引用类型的函数返回一个对象 3用花括号列表初始化一个数组中的元素或一个聚合类中的成员。
与拷贝构造函数对应的就是拷贝赋值运算符
赋值运算符通常返回一个指向其左侧运算对像的引用
合成拷贝赋值运算符如果类未定义一个拷贝赋值运算符那么编译器就会为其生成一个合成拷贝复制运算符。
析构函数析构函数是类的一个成员函数无返回值不接受参数因其不接受参数所以其不能被重载对于一个给定类只会有唯一一个析构函数。
在一个析构函数中不存在类似构造函数中初始化列表中的东西来控制成员如何销毁析构部分是隐式的。成员销毁时发生什么完全依赖于成员的类型。销毁类类型的成员需要执行成员自己的析构函数。内置类型没有析构函数因此销毁内置类型成员什么也不需要做。隐式销毁一个内置指针类型的成员不会delete它所指向的对象。与普通指针不同智能指针是类类型所以具有析构函数。因此智能指针成员会在析构阶段自动销毁。
什么时候回调用析构函数认为非常重要
无论何时想一个对象被销毁就会自动调用其析构函数 (1)变量在离开其作用域时被销毁 2当一个对象被销毁时其成员被销毁 3容器被销毁时其元素被销毁 (4) 对于动态分配的对象当对指向它的指针应用delete运算符时被销毁 5对于临时对象当创建它的完整表达式结束时被销毁。
同样为定义析构函数编译器也会自动生成合成析构函数。
三 / 五法则有三个基本操作可以控制类的拷贝操作拷贝构造函数、拷贝赋值运算符、析构函数。在新标准下一个类还可以定义一个移动构造函数和一个移动赋值运算符。
当我们决定一个类是否要定义他自己版本的拷贝控制成员时一个基本原则是首先确定这个类是否需要一个析构函数。如果需要则几乎可以肯定也需要一个拷贝构造函数和一个拷贝赋值运算符。
合成的析构函数不会delete一个指针数据成员指针所指对象因此此类型的类需要定义一个析构函数。需要拷贝操作的类也需要赋值操作反之亦然。
我们可以通过使用default定义拷贝控制成员来显示的要求编译器生成合成的版本。当我们在类内用default修饰成员的声明时合成的函数将隐式的声明为内联的像任何其他类内声明一样如果我们不希望合成的成员是内联函数应该只对成员的类外定义使用default。我们只能对具有合成版本的成员函数使用default即默认构造函数或拷贝控制成员。
定义删除的函数我们可以通过将拷贝构造函数和拷贝赋值运算符定义为删除的函数delete function来阻止拷贝。删除的函数我们虽然定义了它但不能以任何方式使用它。在函数的参数列表后面加上delete来指出我们希望将它定义为删除的必须出现在该函数的第一次声明时。
注意析构函数是不能定义成删除的成员如果析构函数被删除就无法销毁此类型的对象了对于一个删除了析构函数的类编译器将不允许定义该类型的变量或创建该类型的临时对象但是可以动态分配这种类型的对象不能释放指向该类型动态分配对象的指针。
对于某些类来说编译器将这些合成的成员定义为删除的函数
1、如果类的某个成员的析构函数是删除的或者不可访问的例如是private的则类的合成析构函数被定义为删除的
2、如果类的某个成员的拷贝构造函数是删除的或不可访问的则类的合成拷贝构造函数被定义为删除的。如果类的某个成员的析构函数是删除的或者不可访问的则该类合成的拷贝构造函数也被定义为删除的
3、如果类的某个成员的拷贝赋值运算符是删除的或不可访问的或者类有一个const的或引用成员则类的合成拷贝赋值运算符被定义为删除的
4、如果类的某个成员的析构函数是删除的或者不可访问的或是类有一个引用成员它没有类内初始器或是有一个const成员它没有类内初始器且其类型未显示定义默认构造函数则该类的默认构造函数被定义为删除的。
综上如果一个类内成员的“三’是缺失的或不可访问的则类的相关合成的“三”会被定义为删除的。
类内成员函数可以只声明不定义可以将拷贝赋值运算符和拷贝构造函数声明为private的当未定义时可以阻止任何拷贝该类对象的企图试图拷贝对象的用户代码将在编译阶段被标记为错误成员函数或友元函数中的拷贝操作将会导致链接时错误。
2.拷贝控制与资源管理
当编写赋值运算符时有两点需要记住
1、如果将一个对象赋予它自身赋值运算符必须能正确工作一个好的办法是在销毁左侧运算对象之前拷贝右侧运算对象
2、大多数赋值运算符组合了析构函数和拷贝构造函数的工作。
当编写一个赋值运算符时一个好的模式是将右侧运算对象拷贝到一个局部临时对象中。当拷贝完成后销毁左侧运算对象的现有成员就是安全的了。一旦左侧运算对象的资源被销毁就只剩下将数据从临时对象拷贝到左侧运算对象的成员了。
3.交换操作
对于拷贝控制成员不同swap并不是必要的但是 对于分配了资源的类定义swap可能是一种很重要的优化手段。本节主要内容为swap的定义与应用。
4.拷贝控制实例
本节为Message类和Folder类的定义来处理消息Message为一个存放信息的类Folder为保存Message的类Message类也有一个变量存放本信息存放于那些Folder中。我认为最难得一点就是同步处理Message和Folder。
5.动态内存管理类
某些类需要在运行时分配可变大小的内存空间。这种类通常可以使用标准库容器来保存它们的数据但是某些类需要自己进行内存分配这些类一般来说必须定义自己的拷贝控制成员来管理所分配的内存。默认定义三个指针成员指向其元素所使用的内存elements指向分配的内存中的首元素first_free指向最后一个实际元素之后的位置cap指向分配的内存末尾之后的位置。经常能用到的算法constructpargsp必须是一个类型为调用对象所存对象相同的指针指向一块原始内存args被传递给类型为调用对象的构造函数用来在p所指的内存中构造一个对象allocaten分配一段原始的、未构造的内存保存 n 个类型为调用对象所存对象类型的对像chk_n_alloc()确保有空间容纳新元素
对于移动构造函数move和reallocate比较难懂与重要
首先move是一个标准库函数构造移动构造函数时需要调用move来表示希望使用string或其他类型的移动构造函数如果漏掉了move的调用将会使用string或其他类型的拷贝构造函数当我们使用move时直接调用std::move而不是move。
6.对象移动
右值引用右值引用有一个重要的性质只能绑定到一个将要销毁的对象因此我们可以自由的将一个右值引用的资源“移动”到另一个对象中。
左值和右值是表达式的属性一些表达式生成或要求左值而另一些则生成或要求右值。一般而言一个左值表达式表示的是一个对象的身份而一个右值表达式表示的是对象的值。右值引用可以将其绑定到要求转换的表达式类型形式、字面值常量、或是右值的表达式跟左值引用有着完全相反的绑定特性但是不能将一个右值引用直接绑定到一个左值上。
由于右值只能绑定到临时对象1、所引用的对象将要销毁2、该对象没有其他用户。
这两个特性意味着使用右值引用的代码可以自由地接管所引用的对象的资源。
变量是左值可以看作一个只有运算对象而没有运算符的表达式
变量是左值因此我们不能直接将一个右值引用绑定到一个变量上即使这个变量是右值引用类型也不行。
虽然不能直接将一个右值引用绑定到一定左值上但是我们可以显示地将一个左值转换为对应的右值引用类型。我们还可以通过调用一个名为move的标准库函数来获得绑定到左值上的右值引用。move告诉编译器我们有一个左值但是我们希望像一个右值一样处理它。我们必须认识到调用move就意味着承诺除了对此左值赋值或销毁它外我们将不在使用它。在调用move函数后我们不能对移后源对象的值做任何假设。与大多数标准库函数的使用不同对于move不通过using声明直接调用std::move而不是move。关于其具体工作机制将会在第十六章模版与泛型编程总结。
对于移动操作除非标准库直到我们的移动构造函数不会抛出异常否则他它会认为移动我们的类对象时可能会抛出异常并且为了处理这种可能性而坐一些额外的工作通过在形参列表后写关键字“noexcept”来通知标准库我们的构造函数不会抛出任何异常。不抛出异常的移动构造函数和移动赋值运算符必须标记为“noexcept”。因为标准库容器能对异常发生时其自身的行为提供保障。
与拷贝操作不同编译器根本不会为某些类合成移动构造函数。特别是如果一个类定义了自己的拷贝构造函数、拷贝赋值运算符或者析构函数编译器将不会为他合成移动构造函数和移动赋值运算符了。只有当一个类没有定义任何自己版本的拷贝控制函数且类的每个非static数据成员都可以移动时编译器才会为他合成移动构造函数或者移动赋值运算符。编译器可以移动内置类型的成员。如果一个成员是类类型且该类有对应的移动操作编译器也能移动这个成员。
与拷贝操作不同引动操作永远不会隐式地定义为删除的函数。但是如果我们显示地要求编译器生成default的移动操作且编译器不能移动所有成员时编译器会将移动操作定义为删除的操作。
定义了一个移动构造函数或移动赋值运算符的类必须也定义自己的拷贝操作否则这些成员默认地被定义为删除的。
所有五个拷贝控制成员应该看作一个整体一般来说如果一个类定义了任何一个拷贝操作它就应该定义所有五个操作。
移动迭代器解引用运算符生成一个右值引用通过调用标准库的make_move_iterator函数将一个普通迭代器转换为一个移动迭代器。
对于移动操作的使用要谨慎。
右值和左值引用成员函数我们指出this的左值/右值属性的的方式与定义const成员函数相同即在参数列表后放置一个引用限定符对于限定的函数我们只能将它用于左值对于限定的函数只能用于右值。一个函数可以同时用const和引用限定。在此情况下引用限定符必须跟在const之后。const和引用限定符都可以用来区分重载但如果一个成员函数有引用限定符则具有相同参数列表的所有版本都必须有引用限定符。明天更新下一章节。