您的位置:首页 > 其它

拷贝控制

2016-02-20 15:32 169 查看

1.拷贝控制操作

拷贝构造函数

移动构造函数     //用同类型的对象初始化本对象

拷贝赋值运算符

移动赋值运算符    //将一个对象赋予同类型的另一个对象

析构函数       //销毁对象

注意点:

①如果一个类没有定义所有这些拷贝控制成员,编译器会自动为它定义缺失的操作。

②声明后加=default来显示要求编译器生成合成的版本,只能对具有合成版本的成员函数使用(默认构造函数&拷贝控制成员)。

③声明后加=delete来定义删除的函数,来阻止该函数的调用,可以对任何函数使用,与=default不同。

④< utility >头文件中的move函数调用均采用std::move

⑤swap(a,b); //若a和b均为内置类型,此时会调用标准库std::swap,否则按照匹配程度最优的调用

class A
{
public:
A(const A &a){}                   //拷贝构造函数
A(const A &&a){}                  //移动构造函数
A& operator=(const A &a){}        //拷贝赋值运算符
A& operator=(const A &&a){}       //移动赋值运算符
~A(){}                            //析构函数
};


2.拷贝构造函数

定义:构造函数的第一个参数为自身类类型的引用,且任何额外参数都有默认值。编译器生成的合成拷贝构造函数为浅拷贝

使用拷贝构造函数的情况:

  ①用=定义变量时               //Ta = b;

  ②非引用参数传递              // fcn(T v); fcn(a); 这也是参数第一个为&的原因,否则出现死循环

  ③非引用函数返回              // fcn(){… return v;}

  ④列表初始化数组元素            // T arr[size] = {…}

  ⑤容器元素用非emplace添加         // insert()|push()

  ⑥直接初始化时编译器根据参数匹配调用    // T a(b);编译器使用普通函数匹配

3.拷贝赋值运算符

A a1,a2;
a1 = a2;          //将一个对象赋予同类型的另一个对象


合成的拷贝赋值运算符类似合成的拷贝构造函数。

4.析构函数

  当变量离开作用域、对象销毁时成员销毁、容器销毁时其元素销毁、delete对象指针,析构函数调用,成员按初始化的逆序销毁。

  一个类自定义了析构函数,基本也需要自定义拷贝赋值运算符和拷贝构造函数,反过来却不一定。

5.移动构造函数和移动赋值运算符

  从给定对象窃取资源而不是拷贝资源(指针的移交,之前的指针变量需置nullptr),一般均声明为noexcept(不抛异常,置于参数列表与初始化列表开始的:中间)

  如果一个类定义了自己的拷贝构造函数、拷贝赋值运算符或析构函数,编译器就不会为它合成移动构造函数和移动赋值运算符了。

  移动迭代器解引用生成一个右值引用,通过调用标准库的make_move_iterator函数可将一个普通迭代器转换为一个移动迭代器。copy(make_move_iterator(b),make_move_iterator(e),d);

6.简易的SmartPoint

template<typename T>
class SmartPoint
{
public:
SmartPoint():users(new size_t(1)),p(new T()){}                        //默认构造函数
explicit SmartPoint(T *q):users(new size_t(1)),p(q){}                 //内置指针构造函数
SmartPoint(const SmartPoint &sp):users(sp.users),p(sp.p){++*users;}   //拷贝构造函数
SmartPoint& operator=(const SmartPoint &sp);                          //赋值运算符重载
~ SmartPoint();                                                       //析构函数
private:
size_t *users;
T *p;
};
template<typename T>
SmartPoint<T>& SmartPoint<T>::operator=(const SmartPoint &sp)
{
++*sp.users;    //先对右边指针引用计数+1,解决自我复制存在的问题
if (--*users==0)
{
delete users;
delete p;
}
users = sp.users;
p = sp.p;
return *this;
}
template<typename T>
SmartPoint<T>::~ SmartPoint()
{
if (--*users==0)
{
delete users;
delete p;
}
}


7.引用限定符

引用限定符可以为&&&(成员函数参数列表后),且必须同时出现在函数的声明和定义中。

可以和const结合使用,const限定符置前,引用置后,二者均可以作为重载区分。

&表示仅能通过左值调用该函数,&&表示仅能通过右值调用该函数,const &均可。

如果一个成员函数有引用限定符,则具有相同参数列表的所有版本都必须有引用限定符。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: