C++ Primer : 第十三章 : 拷贝控制之拷贝控制和资源管理
定义行为像值的类
class HasPtr {
public:
	HasPtr(const std::string& s = std::string()) : ps(new std::string(s)), i(0) {}
	HasPtr(const HasPtr& has) : ps(new std::string(*has.ps)), i(has.i) {}
	HasPtr& operator = (const HasPtr& has);
	~HasPtr() { delete ps; }
private:
	std::string* ps;
	int	i;
};
HasPtr::operatpr = (const HasPtr& has) {
	// 先定义一个局部变量保存右侧对象,如果右侧对象和左侧对象是同一个对象,那么先删除右侧对象就会发生错误
	auto newPtr = new std::string(*has.ps);
	// 此时再释放左侧对象资源
	delete ps;
	ps 	= newPtr;
	i 	= has.i;
}
拷贝赋值运算符的实现中,为了安全起见,必须先将右侧对象拷贝到一个局部变量里,然后再删除左侧对象,然后将局部变量赋值给左侧对象。如果先删除左侧对象,此时右侧对象和左侧对象是同一个对象时,就会发生严重错误。
定义行为像指针的类
- 除了初始化对象之外,每个构造函数(拷贝构造函数除外)都要创建一个引用计数,用来记录有多少对象共享正在创建的对象共享状态,当创建一个对象时,引用计数为1,因为此时只有一个对象共享。
 - 拷贝构造函数不分配新得引用计数器,拷贝给定对象的数据成员,包括引用计数器,拷贝构造函数递增共享的计数器,表示给定对象更的状态又被一个新用户所共享
 - 拷贝赋值运算符递减左侧运算对象的引用计数器,递增右侧对象的引用计数器,如果左侧对象的引用计数器为0,则销毁左侧对象。
 - 析构函数判断引用计数是否为0,如果为0,则销毁左侧对象。
 
HasPtr h1;
HasPtr h2(h1);
HasPtr h3(h1);
HasPtr是一个行为像指针的类,新创建的h1的引用计数为1,创建h2,用h1初始化h2,会递增h1的引用计数值,此时h2保存了h1中的引用计数,在创建h3的时候,递增了h1的引用计数值,而且我们必须做的是要更新h2中的引用计数值,此时无法更新h2中的引用计数值。因此,我们需要将引用计数保存在动态内存中,这样原对象和其他副本对象都会指向相同的计数器,这样就可以自动更新引用计数在每个共享对象中的状态。
class HasPtr {
public:
	HasPtr(const std::string& s = std::string()) : ps(new std::string(s)), i(0), use(new size_t(1)) {}
	HasPtr(const HasPtr& has) :  ps(has.ps), i(has.i), use(has.use) { ++ *use;}
	HasPtr& operator = (const HasPtr& has);
	~HasPtr();
private:
	std::strin g* ps;
	int	i;
	size_t* use; // 引用计数
};
HasPtr::HasPtr& operator = (const HasPtr& has) {
	++ *has.use;
	if (0 == *use) {
		delete ps;
		delete use;
	}
	ps 	=	has.ps;
	i	=	has.i;
	use	=	has.use;
	return *this;
}
HasPtr::~HasPtr() {
	if (--*use == 0) {
		delete ps;
		delete use;
	}
}
交换操作
HasPtr temp = 1;
v1 = v2;
v2 = temp;
这样的代码将v1中string拷贝了两次,但是这样做是没有必要的,我们希望swap交换指针,而不是分配string的副本:
std::string* temp = v1.ps;
v1.ps = v2.ps;
v2.ps = temp;
v1.i = v2.i;
我们将swap函数声明为HasPtr类的友元函数,这样swap就能访问HasPtr的ps和i成员:
class HasPtr {
	friend void swap(HasPtr&, HasPtr&);
	// 其他定义
};
inline
void swap(HasPtr& lhs, HasPtr& rhs) {
	using std::swap;
	swap(lhs.ps, rhs.ps);
	swap(lhs.i, rhs.i);
}
在swap函数中:
HasPtr& operator = (HasPtr has) {
	swap(*this, has);
	return *this;
}
在进行HasPtr类的赋值运算中,先将右侧对象拷贝到拷贝赋值运算符函数里,然后交换左侧对象的指针和右侧对象的指针,交换后,右侧对象赋值给了左侧对象,左侧对象相应的string指针也指向了右侧对象副本的对应成员,而右侧对象的string指针则指向了左侧对象的相应成员。在这个函数结束后,右侧对象的副本被销毁,于是原来左侧对象的资源被释放,而左侧对象现在保存的是右侧对象的成员。
C++ Primer : 第十三章 : 拷贝控制之拷贝控制和资源管理的更多相关文章
- C++ Primer : 第十三章 : 拷贝控制之对象移动
		
右值引用 所谓的右值引用就是必须将引用绑定到右值的引用,我们通过&&来绑定到右值而不是&, 右值引用只能绑定到即将销毁的对象.右值引用也是引用,因此右值引用也只不过是对象的别名 ...
 - C++ Primer : 第十三章 : 拷贝控制之拷贝、赋值与销毁
		
拷贝构造函数 一个构造函数的第一个参数是自身类类型的引用,额外的参数(如果有)都有默认值,那么这个构造函数是拷贝构造函数.拷贝构造函数的第一个参数必须是一个引用类型. 合成的拷贝构造函数 在我们没 ...
 - C++Primer 第十三章
		
//1.当定义一个类时,我们显示地或隐式地指出在此类型的对象(注意这里是此类型的对象,而不包括此类型的指针)拷贝,移动,赋值,销毁时做什么.一个类通过定义五种特殊的成员函数来控制这些操作:拷贝构造函数 ...
 - 【C++ Primer 第十三章】4. 拷贝控制示例
		
拷贝控制示例 #include<iostream> #include<string> #include<set> #include<vector> us ...
 - C++ Primer : 第十三章 : 拷贝控制示例
		
/* Message.h */ #ifndef _MESSAGE_H_ #define _MESSAGE_H_ #include <iostream> #include <strin ...
 - C++ Primer : 第十三章 : 动态内存管理类
		
/* StrVec.h */ #ifndef _STRVEC_H_ #define _STRVEC_H_ #include <memory> #include <string> ...
 - 【C++ Primer 第13章】1.  拷贝控制、赋值和销毁
		
拷贝控制.赋值和销毁 如果一个构造函数的第一个参数是自身类的引用,且额外的参数都有默认值,则此构造函数是拷贝控制函数(拷贝构造函数不应该是explicit的). 如果我们没有为一个类定义拷贝构造函数, ...
 - [C++ Primer] : 第13章: 拷贝控制
		
拷贝, 赋值与销毁 当定义一个类时, 我们显示地或隐式地指定在此类型的对象拷贝, 移动, 赋值和销毁时做什么. 一个类通过定义5种特殊的成员函数来控制这些操作, 包括: 拷贝构造函数, 拷贝赋值运算符 ...
 - 【C++】《C++ Primer 》第十三章
		
第十三章 拷贝控制 定义一个类时,需要显式或隐式地指定在此类型地对象拷贝.移动.赋值和销毁时做什么. 一个类通过定义五种特殊的成员函数来控制这些操作.即拷贝构造函数(copy constructor) ...
 
随机推荐
- 解决Jenkins console输出乱码
			
背景 Jenkins console输出乱码,如 ������������� 1 解决办法 Jenkins Master 设置utf8 encoding Tomcat 启动脚本 export JAVA ...
 - laravel多国语言包
			
https://packagist.org/packages/caouecs/laravel-lang 例如安装中文语言包 则下载 zh-CN 拷贝文件到 resouces/lang 下 然后修改co ...
 - 打完补丁后测试db_link对SCN的影响
			
环境:11.2.0.4.0 升 11.2.0.4.8 后测试 背景:oracle 的db_link会导致实例间SCN同步,SCN增长速度过快则会产生错误: 方案:oracle官方推荐升级版本,但升级之 ...
 - null 和 undefined 的区别
			
null表示"没有对象",即该处不应该有值. (1) 作为函数的参数,表示该函数的参数不是对象. (2) 作为对象原型链的终点. undefiend 就是一个缺少值,此处应该有的值 ...
 - git: No refs in common and none specified; doing no
			
用gitolite新建项目,clone后首次push,可能会出现: $ git push No refs in common and none specified; doing nothing ...
 - 联机事务处理OLTP(on-line transaction processing)和联机分析处理OLAP(On-Line Analytical Processing)
			
什么是OLAP(联机分析处理)? 这个是和数据处理非常相关的一个概念.接触过BI(商务智能)的同学一定清楚. 数据处理大致可以分成两大类:联机事务处理OLTP(on-line tr ...
 - PHP数组去重..............过滤字段
			
$test_data = M('hot'); //实例化数据表 $data = $test_data->Distinct(true)->field('descriprion')->o ...
 - PHP的三种输出方式
			
(1)echo 是PHP语句,没有返回值,用于输出一个或多个字符串 (2)print() 是函数,可以有返回值,只能打印出简单类型变量的值,例如int.string (3)print_r() 是函数, ...
 - set集合类型
			
set表示一个集合,相当于C#中的Hashtable,不同的地方在于,所有的值共用一个key. 相关操作如下图.
 - 自定义控件之 RadioList
			
var RadioListObj = function (id, url) { this.URL = url;//radiobox source URL this.ID = id;//radioLis ...