您的位置:首页 > 其它

3月24日学习心得

2018-03-24 23:59 120 查看
  今天,主要是继续学习拷贝控制。在昨天的三/五法则之后,首先是知道使用=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创造了一个副本,这样就可以保证销毁时没有危险。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: