拷贝控制操作,有5个特殊成员函数copy ctor,copy =opt,move ctor,move =opt,dtor

有哪些地方会用到

拷贝初始化
除了=定义变量时
参数传递和函数返回时
花括号列表初始化一个数组中元素或一个聚合类中成员
某些类对所分配的对象使用拷贝初始化,如insert和push;相对地,emplace直接初始化

成员是在析构函数体之后隐含的析构阶段中被销毁的

1一个类需要自定义析构函数,几乎可以肯定它也需要自定义拷贝构造和拷贝赋值。
2拷贝构造和拷贝赋值有一个,几乎可以肯定另一个也需要,但是不一定需要析构函数。
  • 某些类需要阻止拷贝
如iostream类,避免多个对象写入或读取相同的IO缓冲。
定义为删除的函数来阻止拷贝。
struct NoCopy{
NoCopy() = default; //合成的默认构造函数
NoCopy(const NoCopy&) = delete; //阻止拷贝
NoCopy &operator=(const NoCopy&) = delete; //阻止赋值
~NoCopy() = default; //合成版本
//其他
}
=delete必须出现在第一次声明的时候
=delete可以对任意函数指定,但不能删除析构函数 如果一个类有数据成员不能默认构造、拷贝、赋值或销毁,则对应的成员函数将被定义为删除的。 希望阻止拷贝应该用=delete定义,而不应该声明为private,成员函数和友元函数仍然可以进行拷贝。
管理类外资源的类,通常必须定义拷贝控制成员。首先需要确定此类型对象的拷贝语义,一般有两种选择,使类看起来像一个值或者一个指针。
  • 两种类

    • 像值的类:需要深拷贝,定义copy ctor、copy =opt(自赋值)和析构
    • 像指针类:使用shared_ptr来管理资源,使用引用计数,拷贝时修改计数,析构时判断
  • 定义类自己的swap

定义类自己的swap是一种优化手段,应该调用swap而不是std::swap。如果存在类型特定的swap版本,匹配程度会优于std版本。
定义了swap的类通常用swap来定义赋值运算符
HasPtr& HasPtr::operator=(HasPtr ths)
{
swap(*this, ths);//ths现在指向本对象曾经使用的内存,不能交换指针局部变量会被销毁
return *this;//rhs被销毁
}
该方法还自动处理了自赋值情况且是天然异常安全的。
在改变左侧运算对象之前拷贝右侧运算对象
唯一可能抛出异常的是拷贝构造函数中new表达式,真出现也会在改变左侧之前就发生。
  • 引用与move
左值引用,不能绑定到要求转换的表达式、字面值常量、返回右值的表达式。
const左值引用或者右值引用可以绑定到右值上。
区别:左值有持久的状态,右值要么是字面常量,要么是在表达式求值过程中创建的临时对象。
所以右值引用的对象,将要被销毁,且没有其他用户。这就意味着右值引用的代码可以自由地接管所引用对象的资源,“窃取”其状态。 我们可以显式地将一个左值转换为对应的右值引用类型。还可以通过move来获得绑定到左值的右值引用。<utility>
int &&rr3=std::move(rr1);
move告诉编译器,我们有一个左值,但希望像一个右值一样处理它。调用move意味着除了对rr1赋值和销毁外,不能使用它的值。 移动一个对象数据并不会销毁此对象,但有时移动完成后源对象会销毁。所以编写移动操作时,必须确保源对象进入可析构的安全状态,还必须保证对象仍然是有效的(可以安全地赋予新值或者可以安全地使用而不依赖其当前值)。我们的程序不应该依赖于移后源对象的数据。 当编写一个不抛出异常的移动操作的时候,必须在声明和定义中都指定noexcept。
1虽然移动操作通常不抛出异常,但抛出异常是允许的
2标准库容器能对异常发生时自身的行为提供保证。
除非知道移动不会抛出异常,否则必须用拷贝。同样需要检测自赋值,不能再使用右侧资源前就释放左侧资源。 参数是左值,移动版本赋值不可行,不能隐式地将一个右值引用绑定到一个左值。
参数是右值,两个版本都可以,拷贝=需要一次const转换,移动=则是精确匹配。
所有5个拷贝控制成员应该看做一个整体。
  • 移动迭代器
make_move_iterator,解引用后生成一个右值引用。
标准库不保证哪些算法适用于移动迭代器。只有在确信算法在为一个元素赋值或者将其传递给一个用户定义的函数后不再访问它时,才能将移动迭代器传递给算法。 引用限定符& &&,类似const限定符只能用于非static成员函数,且必须同时出现在声明和定义中。const在前,&在后。
对象是一个右值,意味着没有其他用户,因此可以改变对象。

C/C++基础----拷贝控制的更多相关文章

  1. C++ 拷贝控制和资源管理,智能指针的简单实现

    C++ 关于拷贝控制和资源管理部分的笔记,并且介绍了部分C++ 智能指针的概念,然后实现了一个基于引用计数的智能指针.关于C++智能指针部分,后面会有专门的研究. 通常,管理类外资源的类必须定义拷贝控 ...

  2. C++ Primer : 第十三章 : 拷贝控制之对象移动

    右值引用 所谓的右值引用就是必须将引用绑定到右值的引用,我们通过&&来绑定到右值而不是&, 右值引用只能绑定到即将销毁的对象.右值引用也是引用,因此右值引用也只不过是对象的别名 ...

  3. C++ Primer : 第十三章 : 拷贝控制之拷贝控制和资源管理

    定义行为像值的类 行为像值的类,例如标准库容器和std::string这样的类一样,类似这样的类我们可以简单的实现一个这样的类HasPtr. 在实现之前,我们需要: 定义一个拷贝构造函数,完成stri ...

  4. C++的那些事:类的拷贝控制

    1,什么是类的拷贝控制 当我们定义一个类的时候,为了让我们定义的类类型像内置类型(char,int,double等)一样好用,我们通常需要考下面几件事: Q1:用这个类的对象去初始化另一个同类型的对象 ...

  5. C++ Primer : 第十三章 : 拷贝控制之拷贝、赋值与销毁

    拷贝构造函数 一个构造函数的第一个参数是自身类类型的引用,额外的参数(如果有)都有默认值,那么这个构造函数是拷贝构造函数.拷贝构造函数的第一个参数必须是一个引用类型. 合成的拷贝构造函数   在我们没 ...

  6. Chapter13:拷贝控制

    拷贝控制操作:拷贝构造函数.拷贝赋值运算符.移动构造函数.移动赋值运算符.析构函数. 实现拷贝控制操作的最困难的地方是首先认识到什么时候需要定义这些操作. 拷贝构造函数: 如果一个构造函数的第一个参数 ...

  7. c/c++ 拷贝控制 构造函数的问题

    拷贝控制 构造函数的问题 问题1:下面①处的代码注释掉后,就编译不过,为什么??? 问题2:但是把②处的也注释掉后,编译就过了,为什么??? 编译错误: 001.cpp: In copy constr ...

  8. c/c++ 拷贝控制 右值与const引用

    拷贝控制 右值与const引用 背景:当一个函数的返回值是自定义类型时,调用侧用什么类型接收?? 1,如果自定义类型的拷贝构造函数的参数用const修饰了:可以用下面的方式接收. Test t2 = ...

  9. C++ Primer 笔记——拷贝控制

    1.如果构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数.拷贝构造函数的第一个参数必须是引用类型(否则会无限循环的调用拷贝构造函数). 2.如果没有为一个类 ...

随机推荐

  1. web.net用户控件

    1.它是以 Control注册 <%@ Control Language="C#" AutoEventWireup="true" CodeBehind=& ...

  2. 快排 - 快速排序算法 (Chinar出品 简单易懂)

    Quicksort 快排的简单讲解 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...

  3. 极大极小搜索思想+(α/β)减枝 【转自-----https://blog.csdn.net/hzk_cpp/article/details/79275772】

    极大极小搜索,即minimax搜索算法,专门用来做博弈论的问题的暴力. 多被称为对抗搜索算法. 这个搜索算法的基本思想就是分两层,一层是先手,记为a,还有一层是后手,记为b. 这个搜索是认为这a与b的 ...

  4. 矩阵快速幂 51nod

    基准时间限制:3 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 给出一个N * N的矩阵,其中的元素均为正整数.求这个矩阵的M次方.由于M次方的计算结果太大,只需要输出 ...

  5. IDLE的使用

    为什么要用IDE? 到现在为止,我们也是写过代码的人啦,但你有没有发现,每次写代码要新建文件.写完保存时还要选择存放地点,执行时还要切换到命令行调用python解释器,好麻烦呀,能否一气呵成,让我简单 ...

  6. set 基础知识

    #include <iostream> #include <set> using namespace std; int main() { set<int> s; s ...

  7. 《DSP using MATLAB》Problem 6.6

    代码: %% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %% Output In ...

  8. 直面Java 第004期。

    什么是值传递,什么是引用传递.为什么说Java中只有值传递 对于初学者来说,要想把这个问题回答正确,是比较难的.在第二天整理答案的时候,我发现我竟然无法通过简单的语言把这个事情描述的很容易理解,遗憾的 ...

  9. LG4781 【模板】拉格朗日插值

    题意 题目描述 由小学知识可知,$n$个点$(x_i,y_i)$可以唯一地确定一个多项式 现在,给定$n$个点,请你确定这个多项式,并将$k$代入求值 求出的值对$998244353$取模 输入输出格 ...

  10. day3 zookeeper

    PS:在生产的场景中,一般有两个需求:1.提供设备的注册 2.对所注册的接口进行监听.zookeeper就是提供这样的功能,它本身就是一个集群,如果存在半数以上的节点活着就能提供服务,本身就具备很高的 ...