复制控制+智能指针

来源:互联网 发布:唱吧网络链接失败 编辑:程序博客网 时间:2024/04/29 23:09

今天把c++ primer的13章看了,总结一下。

一:复制控制

1:复制控制就是复制构造函数、赋值操作符、析构函数的总称。他们有一定的相似性,所以统称为“复制控制”。

他们的共性是什么呢?

a:如果自己没定义,系统会自动合成;

b:对于类的对象成员中有指针的情况,一般都要定义这三者。而且如果要定义析构函数就一定要定义复制构造函数和赋值操作符,这个叫“三法则”。

不同点:

复制构造函数和赋值操作符如果自己定义了,系统就不会合成,但是析构函数系统始终会合成。(p-414)利用复制构造函数和赋值操作符的特点,可以对于不能够赋值的进行避免赋值。我们可以只申明不定义,这样可以避免系统合成,我们自己也不操作就达到了目的。

2:为什么要用复制构造函数

什么时候要定义复制构造函数和赋值操作符

一般来讲,当类的数据成员有指针变量,或者对对象有特殊操作时需要定义复制构造函数和赋值操作符。下面是个类的数据成员有指针变量的列子。

程序如下:

#include <stdio.h>#include <string>#include <iostream>using namespace std;struct NoName{public:NoName(std::string *str_f,int i_f,double d_f):pstring(str_f),i(i_f),d(d_f){};NoName(const NoName &a){pstring=new std::string;*(this->pstring)=*(a.pstring);this->i=a.i;this->d=a.d;}public:std::string *pstring;int i;double d;};int main(){string a(4,'x');string b(4,'y');string *str_a=&a;//string和数组还不同NoName Object1(str_a,2,3.0);NoName Object2(Object1);*(Object2.pstring)=b;cout<<*(Object1.pstring)<<endl;system("pause");return 1;}

对于这种含有指针成员的类,因为在复制是只复制指针地址,所以他们其实是公用一个基的。这种改变内容而改变其他对象的内容到不可怕,可怕的是在删除时引起的指针悬挂。

二、指针悬挂与智能指针

指针悬挂也称为“野指针”,是只在指针所指内存被删除后指针的指向不确定的情况。对于这种指针,我们其实是可以访问的,但是得到的值不一定每次一样,因为这时候指针指的方向其实是不定的。但是我们不能对其所指内容进行操作,比如修改里面的值或者删除等等。也就是说,看看可以,但是没有操作权限

为了解决指针悬挂,可以由两种方法。

a:构造复制构造函数

这种方法是对于每个指针就行复制操作,这样通过改变其他对象的指针就不能影响到别的。

b:利智能指针

智能指针可以解决指针悬挂的问题,但是其不能解决因为改变一个对象的值而影响其他对象值的问题。那么什么是智能指针呢?在c++ primer(p-423)中很清楚的阐明了什么是智能指针和怎么构造一个智能指针。其代码如下:


class U_Ptr{friend class HasPtr;U_Ptr(int *p):ip(p),use(1){}~U_Ptr(){delete ip;}int *ip;size_t use;};class HasPtr{public:HasPtr(int *p,int i):ptr(new U_Ptr(p)),val(i){}HasPtr(const HasPtr &orig):ptr(orig.ptr),val(orig.val){orig.ptr->use++;}HasPtr& operator=(const HasPtr &rhs);~HasPtr(){if(--ptr->use==0) delete ptr;}private:U_Ptr *ptr;int val;};HasPtr& HasPtr::operator =(const HasPtr &rhs){rhs.ptr->use++;if(--this->ptr->use==0)delete this;this->ptr=rhs.ptr;this->val=rhs.val;return *this;}


这里说明一下几点:

1:智能指针是联系对象和所属单元的纽带,其本质上是起一个过渡作用;

2:智能指针只用于HasPtr类,我们并不希望用户用它。因此,我们把其所有数据定义为private,并且把HasPtr定义为其友元;

3:在这里补充两点与上没有关系的两个知识点

1):new U_Ptr(p)是新建一个U_Ptr对象,其参数要求是和U_Ptr的构造函数形式息息相关

2):友元类表达的意思是可以让友元类中该对象访问其类中的私有函数,也就是说任何类的成员只能其对象才可以访问,这点是没有商量的余地的。

三:补充介绍一下赋值操作符和析构函数

赋值操作符和复制构造函数情况差不多,这里略去。主要介绍一下析构函数。

1:析构函数的作用

析构函数和构造函数相对应,其是用于释放空间的。但是因为一般系统会自动合成析构函数,那么我们在什么情况下还需要自己定义析构函数呢?

2:什么时候定义析构函数

对于“对象引用或者对象指针”和“动态申请的对象”需要手动删除,这时候一般就需要用析构函数。或者我们想在对象删除的同时,做点其他操作,这是也可以通过析构函数完成。而其他一般都可以通过析构函数解决。