C++ Primer Notes(13)

来源:互联网 发布:日常悠哉大王知乎 编辑:程序博客网 时间:2024/06/06 13:17

1.拷贝构造函数的第一个参数必须是一个引用类型。

2.拷贝初始化通常用拷贝构造函数完成,但是如果一个类有一个移动构造函数,则拷贝初始化有时会使用移动构造函数而非拷贝构造函数来完成。

3.拷贝初始化发生:

a.用=定义变量;

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

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

。。。

4.在函数调用过程中,具有非引用类型的参数要进行拷贝初始化,当一个函数具有非引用返回的类型时,返回值会被用来初始化调用方的结果。

5.拷贝构造函数被用来初始化非引用类类型参数,如果其参数不是引用类型,则调用永远不会成功---为了调用拷贝构造函数,我们必须拷贝它的实参,但为了拷贝实参,我们又需要调用拷贝构造函数,如此无限循环。


6.拷贝赋值运算符接受一个与其所在类相同类型的参数,为了与内置类型的赋值保持一致,赋值运算符通常返回一个指向其左侧运算对象的引用。


7.析构函数与构造函数进行相反的操作:构造函数初始化对象的非static数据成员,还可能做一些其他工作;析构函数释放对象使用的资源,并销毁对象的非static数据成员。

8.析构函数是类的成员函数,没有返回值,不接受参数,不能被重载。

9.在对象最后一次使用之后,析构函数的函数体可执行类设计者希望执行的任何收尾工作。通常,析构函数释放对象在生存期分配的所有资源。

10.析构部分是隐式的,成员销毁时发生什么完全依赖于成员的类型。销毁类类型的成员需要执行成员自己的析构函数 ,内置类型没有析构函数,因此销毁内置类型成员什么也不需要做。

11.隐式地销毁一个内置指针类型的成员不会delete它所指向的对象。

12.什么时候会调用析构函数:无论何时一个对象被销毁,就会自动调用其析构函数,用来销毁对象的非static数据成员,释放对象使用的资源:

变量在离开其作用域时被销毁;

当一个对象被销毁时,其成员被销毁;

容器被销毁时,其元素被销毁;

对于动态分配的对象,当对指向它的指针应用delete运算符时被销毁;

对于临时对象,当创建它的完整表达式结束时被销毁;

13.析构函数体自身并不直接销毁成员,成员是在析构函数体之后隐含的析构阶段中被销毁的。

14.如果一个类需要自定义的析构函数,几乎可以肯定它也需要自定义拷贝赋值运算符和拷贝构造函数。

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


16.在新标准发布之前,类是通过将其拷贝构造函数和拷贝赋值运算符声明为private的来阻止拷贝。声明但不定义它们。

希望阻止拷贝的类应该使用=delete来定义它们自己的拷贝构造函数和拷贝赋值运算符,而不应该将它们声明为private的。


17.赋值运算符通常组合了析构函数和构造函数的操作,类似析构函数,赋值操作会销毁左侧运算对象的资源,类似拷贝构造函数,赋值操作会从右侧运算对象拷贝数据。最好是先将右侧运算对象拷贝到一个局部临时对象中,当拷贝完成后,销毁左侧运算对象的现有成员就是安全的了。

18.行为像值的类:对于类管理的资源,每个对象有应有一份自己的拷贝。假如类有指针成员,对于指针指向的数据,每个对象都必须有一份自己的拷贝,而不是仅仅拷贝指针本身;eg:

class Hasptr{

public:

   Hasptr(const string &s=string()):ps(new string(s),i(0)  { }//如果写成ps(s),则ps和s指向同一个对象,不是行为像值的类。

   Hasptr(const Hasptr &p) :ps(new string(*p.ps)),i(p.i) { }

   Hasptr& operator=(const Hasptr &);

   ~Hasptr() {delete ps;}//隐式销毁一个内置指针类型的成员不会delete它指向的对象,所以需要显示的delete ps指向的对象。

private:

   string *ps;

   int    i;

};

Hasptr&  Hasptr::operator=(const Hasptr &r)

{

   i=r.i;

   auto tmp=new string(*r.ps));

   delete ps;//释放旧内存,因为 隐式销毁一个内置指针类型的成员不会delete它指向的对像。

   ps=tmp;

   delete tmp;

   return *this;

}