来源
由于拷贝控制操作是由三个特殊的成员函数来完成的,所以我们称此为“C++三法则”。在较新的 C++11 标准中,为了支持移动语义,又增加了移动构造函数和移动赋值运算符,这样共有五个特殊的成员函数,所以又称为“C++五法则”。也就是说,“三法则”是针对较旧的 C++89 标准说的,“五法则”是针对较新的 C++11 标准说的。为了统一称呼,后来人们把它叫做“C++ 三/五法则”。
CPP拷贝构造
这个命名,原来看c++ primer的时候,搞的我有点晕,今天梳理一下:
这个命名可以看做 内容来源
+ 内容去向
来看.
内容来源分类两个:1.copy旧资源(拷贝) 2.move旧资源(移动)
内容去向分为两个:1.new 新的内容 (构造) 2.cove 旧内存(赋值)
上面组合一下就可以得到4个需要定义个拷贝构造函数,拷贝赋值函数,移动构造函数,移动赋值函数.再加上一个默认构造函数.
其他的一些规律:
- 构造函数都是没有返回值的
- 赋值函数需要返回this指针,为了实现a = b = c连续赋值操作.
- 拷贝函数输入参数都是常引用,因为不会修改原来的内容,就是copy一下.
3/5法则
- 需要析构函数的类也需要拷贝构造函数和拷贝赋值函数。(同时定义这三个函数)
- 需要拷贝操作的类也需要赋值操作,反之亦然。
- 析构函数不能是删除的
- 如果一个类有删除的或不可访问的析构函数,那么其默认和拷贝构造函数会被定义为删除的。
- 如果一个类有const或引用成员,则不能使用合成的拷贝赋值操作。
案例1:
注意:这里vector里面没有定义拷贝构造函数,拷贝赋值也没有.只有一个基础的构造函数,用于分配内存.
1.是浅拷贝 2.double free的问题.
解决方法:
1.禁止浅拷贝
2.定义拷贝构造函数,重新分配内存,把来源内容拷贝到新内存中去.
cpp中默认构造函数的关系
第二案例:
有定义三个函数
class Car //A very simple class just to demonstrate what these definitions mean.
//It's pseudocode C++/Javaish, I assume strings do not need to be allocated.
{
private String sPrintColor;
private String sModel;
private String sMake;
public changePaint(String newColor)
{
this.sPrintColor = newColor;
}
public Car(String model, String make, String color) //Constructor
{
this.sPrintColor = color;
this.sModel = model;
this.sMake = make;
}
public ~Car() //Destructor
{
//Because we did not create any custom types, we aren't adding more code.
//Anytime your object goes out of scope / program collects garbage / etc. this guy gets called + all other related destructors.
//Since we did not use anything but strings, we have nothing additional to handle.
//The assumption is being made that the 3 strings will be handled by string's destructor and that it is being called automatically--if this were not the case you would need to do it here.
}
public Car(const Car &other) // Copy Constructor
{
this.sPrintColor = other.sPrintColor;
this.sModel = other.sModel;
this.sMake = other.sMake;
}
public Car &operator =(const Car &other) // Assignment Operator
{
if(this != &other)
{
this.sPrintColor = other.sPrintColor;
this.sModel = other.sModel;
this.sMake = other.sMake;
}
return *this;
}
}
Car car1 = new Car("mustang", "ford", "red");
Car car2 = car1; //Call the copy constructor
car2.changePaint("green");
//car2 is now green but car1 is still red.
没有定义这三个函数
class Car //A very simple class just to demonstrate what these definitions mean.
//It's pseudocode C++/Javaish, I assume strings do not need to be allocated.
{
private String sPrintColor;
private String sModel;
private String sMake;
public changePaint(String newColor)
{
this.sPrintColor = newColor;
}
public Car(String model, String make, String color) //Constructor
{
this.sPrintColor = color;
this.sModel = model;
this.sMake = make;
}
public ~Car() //Destructor
{
//Because we did not create any custom types, we aren't adding more code.
//Anytime your object goes out of scope / program collects garbage / etc. this guy gets called + all other related destructors.
//Since we did not use anything but strings, we have nothing additional to handle.
//The assumption is being made that the 3 strings will be handled by string's destructor and that it is being called automatically--if this were not the case you would need to do it here.
}
}
//Shallow copy example
//Assume we're in C++ because it's standard behavior is to shallow copy objects if you do not have a constructor written for an operation.
//Now let's assume I do not have any code for the assignment or copy operations like I do above...with those now gone, C++ will use the default.
Car car1 = new Car("ford", "mustang", "red");
Car car2 = car1;
car2.changePaint("green");//car1 is also now green
delete car2;/*I get rid of my car which is also really your car...I told C++ to resolve
the address of where car2 exists and delete the memory...which is also
the memory associated with your car.*/
car1.changePaint("red");/*program will likely crash because this area is
no longer allocated to the program.*/
reference
C++之三五法则
stackOverFlow:What is The Rule of Three?
stackOverFlow: What is the copy-and-swap idiom?
双笙子佯谬【公开课】第02讲:RAII与智能指针