3月24日学习心得

  今天,主要是继续学习拷贝控制。在昨天的三/五法则之后,首先是知道使用=default是用合成版本的函数。之后,要明确我们定义的拷贝构造函数或者拷贝赋值运算符有些时候是要阻止拷贝的。在两者后=default即使得定义存在,但之后无法调用,从而实现删除函数。

e.g.

struct nocopy{
	public:
	nocopy(){
	cout<<"nocopy constructed"<<endl;
	}
	~nocopy(){
		cout<<"nocopy destructed"<<endl;
	}
	private:
	int sum=0;
	nocopy(const nocopy&);
	nocopy& operator=(const nocopy&);
};
struct Employee{
	Employee(){
		name="Unknown";
		id++;
		myid=id; 
	}
	Employee(const string s)
	{
		name=s;
		id++;
		myid=id;
	}
	static	int id;
	Employee(const Employee& turename)
	{
		myid=turename.myid;
		name=turename.name;
	}
	void print()
	{
		cout<<name<<" has id "<<myid<<endl;
	}
	private:
	int myid;
	string name;
};
int Employee::id=0;

注意=default和=delete的重要不同在于,编译器生成代码时才会用=default,但=delete必须一定义就使用。

析构函数不能是删除的成员。

如果一个类有数据成员不能默认构造,拷贝,复制或销毁,则对应的成员函数将被定义为删除的。

在以往的版本中常使用将拷贝构造函数和拷贝赋值运算符声明在private中以删除。


13.2

一个类可能有两种拷贝语意,一种是值的,一种是类指针的。

下面是一个行为像值的类的列子

class HasPtr {
friend void swap(HasPtr &lhs,HasPtr &rhs);
public:
	HasPtr(const string &s,int f):ps(new string(s)),i(f),use(new int(1)){}
	HasPtr(const HasPtr&hp):ps(hp.ps),i(hp.i),use(hp.use){++*use;}
	HasPtr& operator=(const HasPtr &rhs){
		++*rhs.use;
		ps=rhs.ps;
		if(--*use==0)
		{
			delete ps;
			delete use;
		}
		i=rhs.i;
		use=rhs.use;
		return *this;
	};
	HasPtr& operator=(HasPtr rhs){
		swap(*this,rhs);
		return *this;
	}//拷贝并交换,非常安全
	bool operator<(HasPtr &rhs)
	{
		if(i<rhs.i)
		return true;
		else
		return false;
	}
	void print(){
		cout<<*ps<<endl;
		cout<<i<<endl;
		cout<<endl;
	}
	~HasPtr() {
	if(--*use==0)
	{
	delete ps;
	delete use;
	}
	}
private:
	string *ps;
	int i;
	int *use;
};
inline
void swap(HasPtr &lhs,HasPtr &rhs)
{
		using std::swap;
		swap(lhs.ps,rhs.ps);
		swap(lhs.i,rhs.i);
		cout<<"swap happens here"<<endl;
}
有两点需特别注意:

1.自赋值必须正确工作

2.大多数赋值运算符组合了析构函数和拷贝函数的工作


类指针方式,以下为一例子

class TreeNode{
	public:
	TreeNode():left(nullptr),right(nullptr),count(1){ }
	TreeNode(string val):value(val),left(nullptr),right(nullptr),count(1){ }
	TreeNode(string val,TreeNode *tleft,TreeNode *tright):value(val),count(1),left(tleft),right(tright){ }
	TreeNode(const TreeNode& treeNode){
		value=treeNode.value;
		count=treeNode.count;
		++count;
		left=treeNode.left;
		right=treeNode.right;
	}
	TreeNode& operator=(const TreeNode& treeNode)
	{
		value=treeNode.value;
		count=treeNode.count;
		++count;
		left=treeNode.left;
		right=treeNode.right;
	}
	void print()
	{
		cout<<value<<endl;
		cout<<count<<endl;
	}
	void show_leave()
	{
		cout<<left->value<<"      "<<right->value<<endl;
	}
	private:
		string value;
		int count;
		TreeNode *left;
		TreeNode *right;
};

class BinStrTree{
	public:
		BinStrTree()=default;
		BinStrTree(TreeNode *rt):root(rt){ };
		BinStrTree(const BinStrTree&)=delete;
		BinStrTree& operator=(const BinStrTree&)=delete;
	private:
		TreeNode *root;
};

注意,在指针方式中引用计数特别重要,它决定了动态内存的分配与销毁。


13.3交换操作

有时为了达到目的我们不能使用标准sort,必须使用自己定义的sort排序。对于类值类型尤其要这样做,上述的HasPtr即为一例。swap中交换了两个对象的指针,使得排序高速进行。还有H在有HasPtr的情况下,HasPtr的sort优先级高于标准sort.注意其中特殊的操作:拷贝并交换。rhs创造了一个副本,这样就可以保证销毁时没有危险。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值