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创造了一个副本,这样就可以保证销毁时没有危险。
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创造了一个副本,这样就可以保证销毁时没有危险。
相关文章推荐
- c++学习心得
- redis学习心得之三-【java操作redis】
- 学习c++和DirectX的几点心得
- S3c2410 LCD驱动学习心得
- [剑指offer学习心得]之:二维数组中的查找
- MapXtreme 2005 学习心得 使用WebTool工具(七)
- Internet路由结构学习心得一:通告汇聚和具体路由影响AS入流量1
- 学习心得 五
- redis学习心得之二【redis主从配置】
- 【Monkeyrunner 小白入门示例】算是新秀的学习心得吧
- 开始学习C++心得实例(2)
- 关联容器的学习心得
- SET IDENTITY_INSERT 学习心得
- 学习飞机游戏的心得
- mybatis-spring官网学习心得
- [ACM学习心得]关于sync_with_stdio(false);
- 【正则[规则]表达式学习心得】1、悟透普通字符-字符直接量
- threejs学习心得(场景的搭建+运动模型导入)
- PAXOS学习心得
- 程序渣自学一些心得_读书和学习