今天把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:什么时候定义析构函数
对于“对象引用或者对象指针”和“动态申请的对象”需要手动删除,这时候一般就需要用析构函数。或者我们想在对象删除的同时,做点其他操作,这是也可以通过析构函数完成。而其他一般都可以通过析构函数解决。