zoukankan      html  css  js  c++  java
  • 拷贝控制和资源管理

    类的行为可以像一个值或指针:

    类的行为像一个值,意味着它应该也有自己的状态。当我们拷贝一个像值得对象时,副本与原对象是独立的,改变副本不会对原对象有任何影响,反之亦然。

    类的行为像指针,将共享状态,拷贝这样的一个类的对象时,副本和原对象使用相同的底层数据,改变副本也会改变原对象,反之亦然。

    行为像值的类

    提供类值的行为,对于类管理的资源,每个对象都应该拥有一份自己的拷贝。

    class Hasptr{
    public:
    	Hasptr(const std::string &s=std::string()):ps(new std::string(s)),i(0){}
    	Hasptr(const Hasptr &p):ps(new std::string(*p.ps)),i(p.i){}
    	Hasptr& operator=(const Hasptr&);
    	~Hasptr(){delete ps;}
    private:
    	std::string *ps;
    	int i;
    }
    
    

    类值拷贝赋值运算符

    赋值运算符组合了析构函数和构造函数的操作:

    • 类似析构函数,赋值操作会销毁左侧运算对象的值;
    • 类似拷贝构造函数,赋值操作会从右侧对象拷贝数据。

    需要注意的是:

    • 如果将一个对象赋予自身,赋值运算符必须能正常工作;
    • 异常安全,即当异常发生时,能将左侧运算对象置于一个有意义的状态。
    Hasptr& Hasptr::operator = (const Hasptr &rhs)
    {
    	auto newp =  new string(*rhs.ps);	//拷贝底层的string
    	delete ps;		//释放旧内存
    	ps = newp;		//右侧对象拷贝数据到本对象
    	i = rhs.i;
    	return *this;	//返回本对象
    }
    
    

    行为像指针的类

    引用计数

    引用计数的工作方式如下:

    • 除了初始化对象外,每个构造函数(拷贝构造函数除外)还要构建一个引用计数,用来记录有多少对象与正在创建的对象共享状态。当创建一个对象时,只有一个对象共享状态,将此计数器初始化为1。
    • 拷贝构造函数不分配新的计数器,而是拷贝给定对象数据成员,包括计数器。拷贝构造函数递增共享的计数器,指出给定对象的状态又被一个新的用户所共享。
    • 析构函数递减计数器,指出共享状态的用户少了一个,如果计数器为0,则析构函数释放状态。
    • 拷贝赋值运算符递增右侧运算对象的计数器,递减左侧运算对象的计数器。如果左侧运算对象的计数器为0,意味着它的共享状态没有用户了,拷贝赋值运算符就必须销毁状态。

    计数器不能是 Hasptr 对象的成员:

    Hasptr p1("Hiya");
    Hasptr p2(p1);	
    Hasptr p3(p1);	//p1,p2,p3指向相同的string
    
    

    如果引用计数保存在每个对象中,当创建 p3 时,可以递增 p1 中的计数器并将其拷贝到 p3,但是 p2 中的计数器无法更新。

    解决办法是将计数器保存在动态内存中,当创建一个对象时,也分配一个新的计数器,当拷贝或赋值对象时,拷贝指向计数器的指针,使用此方法可以保证副本和原对象指向相同的计数器。

    定义一个使用引用计数的类

    class Hasptr
    {
    public:
    	Hasptr(const std::string &s = std::string()):ps(new std::string(s),i(0),use(new std::size_t(1))){}
    	Hasptr(const Hasptr &p):ps(p.ps),i(p.i),use(p.use){++*use};
    	Hasptr& operator=(const Hasptr&);
    	~Hasptr();
    private:
    	std::string *ps;
    	int i;
    	std::size_t *use;
    }
    
    

    析构函数需要检查引用计数是否为0:

    Hasptr ::~Hasptr()
    {
    	if(--*use == 0){
    		delete ps;
    		delete use;
    	}
    }
    
    

    拷贝赋值运算符:

    Hasptr& Hasptr::operator=(const Hasptr& rhs)
    {
    	++*rhs.use;		//递增右侧对象的引用计数
    	if(--*use == 0)	//递减和检测本对象的引用计数
    	{
    		delete ps;
    		delete use;
    	}
    	
    	ps = rhs.ps;
    	i = rhs.i;
    	use = rhs.use;
    	
    	return *this;
    }
    
  • 相关阅读:
    PAT (Advanced Level) Practice 1055 The World's Richest (25 分) (结构体排序)
    PAT (Advanced Level) Practice 1036 Boys vs Girls (25 分)
    PAT (Advanced Level) Practice 1028 List Sorting (25 分) (自定义排序)
    PAT (Advanced Level) Practice 1035 Password (20 分)
    PAT (Advanced Level) Practice 1019 General Palindromic Number (20 分) (进制转换,回文数)
    PAT (Advanced Level) Practice 1120 Friend Numbers (20 分) (set)
    从零开始吧
    Python GUI编程(TKinter)(简易计算器)
    PAT 基础编程题目集 6-7 统计某类完全平方数 (20 分)
    PAT (Advanced Level) Practice 1152 Google Recruitment (20 分)
  • 原文地址:https://www.cnblogs.com/xiaojianliu/p/12496728.html
Copyright © 2011-2022 走看看