C++中拷贝构造函数、拷贝赋值运算符、析构函数、移动构造函数、移动赋值运算符(三/五法则)

news2024/11/16 5:22:10

1、介绍

三五法则是针对C++中类的成员和类对象的操作函数。

三法则是指:拷贝构造函数、拷贝赋值运算符、析构函数。

五法则是在三法则的基础上增加了:移动构造函数、移动赋值运算符。

2、拷贝构造函数

定义:如果构造函数的第一个参数是自身类类型的引用,且任何额外的参数都有默认值,则该构造函数时拷贝构造函数。如果没有为类定义拷贝构造函数,则编译器会默认生成拷贝构造函数。

用途:定义已存在的类对象,去初始化该类的新对象的成员初始化过程。

eg:

class Foo
{
  public:
    Foo(); //默认构造函数
    Foo(const Foo&);    //拷贝构造函数
    //.....    
}

拷贝初始化和直接初始化差异:

string dots(9,'.');    //直接初始化
string s(dots);        //直接初始化
string s2 = dots;      //拷贝初始化
stirng null_book = "hello world";    //拷贝初始化
string nines=string("9",'.');    //拷贝初始化

直接初始化是编译器选择与我们提供参数最匹配的构造函数来进行初始化。拷贝初始化是指将右侧运算对象拷贝到正在创建的对象中。注意两点:正在创建的对象、赋值符号=。

拷贝构造函数调用的情况有以下几种:

(1)使用“=”符号定义变量。

(2)将一个对象作为实参传递给一个非引用类型的形参。

(3)从一个返回类型为非引用类型的函数返回一个对象。

(4)用花括号列表初始化一个数组中的元素或一个聚合类中的成员。

3、拷贝赋值运算符

定义:重载类对象赋值操作符“=”的函数,就是拷贝赋值运算符。简单的说就是重载运算符函数。形式如下:

class Foo
{
  public:
    Foo(); //默认构造函数
    Foo(const Foo&);    //拷贝构造函数
    Foo& operator=(const Foo&);    //拷贝赋值运算符
    //.....    
}

Foo& Foo::operator=(const Foo& org)
{
    //.....
    return *this;    //注意:拷贝赋值运算符应该返回一个指向其左侧预算对象的引用this。
}

4、析构函数

定义:释放对象使用的资源,并销毁对象的非static数据成员。

class Foo
{
    public:
    Foo(); //默认构造函数
    Foo(const Foo&);    //拷贝构造函数
    Foo& operator=(const Foo&);    //拷贝赋值运算符
    ~Foo();    //析构函数
    int* ps;
    //.....    
};
Foo::~Foo()
{
    delete ps; 
}

注意:一个类中构造函数可以有多个,析构函数只有一个。智能指针时类类型,具有析构函数,所以在析构阶段会自动销毁,不需要手动释放,释放的一般都是new,malloc手动分配的堆内存。

5、 什么时候定义拷贝构造函数和拷贝赋值运算符呢?

通常,如果类需要定义析构函数,则该类就需要定义:拷贝构造函数和拷贝赋值运算符。

或者说,如果类的成员里面由指针成员变量,则该类需要定义:析构函数、拷贝构造函数、拷贝赋值运算符。(如果类的对象之间不存在赋值和初始化操作,则不用定义拷贝构造函数、拷贝赋值运算符,也应该阻止编译器生成默认的拷贝和赋值函数,阻止的方法是在函数的参数列表后面加上=delete。但该定义析构函数的情况,还是需要定义析构函数释放内存。)

class Foo
{
    public:
    Foo(); //默认构造函数
    Foo(const Foo&)=delete;    //阻止类对象的拷贝
    Foo& operator=(const Foo&)=delete;    //阻止类对象赋值
    ~Foo();    //析构函数
    //.....    
};

6、移动构造函数、移动赋值运算符

 简单的来说就是将一个原先对象的管理权移动到另一个新对象上。原先被对象则不可再用,因为管理权已移动到新的对象上!!!

移动构造函数和移动赋值运算符的优点是不用深拷贝数据,直接将原先的对象数据移动到新的对象上,提高了效率。

demo如下:

#include <iostream>
#include <string>

class SaleItem
{
    public:
        //1 如果有多个构造函数时,仍需要编译器默认的构造函数,则可以在声明时,在()后面加default,表示使用系统生成的默认构造函数。
        //1 这种在声明时,写=default,表示构造函数为类的内联函数;如果不想用内联函数,在声明和定义分开写。
        //1 默认的构造函数的形参为空。
        SaleItem(){m_name = new int(10);};

        //2 拷贝构造函数用于类类型对象的初始化操作。如果不定义会默认生成。

        SaleItem(const SaleItem&);

        //3、拷贝赋值运算符
        SaleItem& operator=(const SaleItem& orig);

        //4、析沟函数
        ~SaleItem(){if(m_n1 != NULL){delete m_name;m_name = NULL;} std::cout << " ~~~~free memory " << std::endl;};
    void PrintMem(){std::cout << "m_n1 " << m_n1 << " m_n2 " << m_n2  << " m_name "<< *m_name << std::endl;}

        //5、移动构造函数
        SaleItem(SaleItem &&orig);

        //6、移动赋值函数
        SaleItem& operator=(SaleItem&& orig);

    int m_n1=10; 
    int m_n2 = 1;
    int *m_name = NULL;

};
SaleItem::SaleItem(const SaleItem& orig)
{
    m_n1 = orig.m_n1+2;
    m_n2 = orig.m_n2 *2;
    auto newName = new int(*orig.m_name);   //创建临时变量保存数据并开辟内存
    if(m_name != NULL)
    {
        delete m_name;  //释放原内存的释放
        m_name = NULL;
    }
    m_name = newName;
    std::cout << "Copy Constructor " << std::endl;
}

SaleItem& SaleItem::operator=(const SaleItem& orig)
{
    std::cout << "Copy Assignment======= " << std::endl;
    auto newName = new int(*orig.m_name);   //创建临时变量保存待赋值数据并开辟内存,
    if(m_name != NULL)
    {
        delete m_name;  //释放原内存的释放
        m_name = NULL;
    }
    m_name = newName;
    return *this;
}

 SaleItem::SaleItem(SaleItem &&orig)
 {
    m_name = NULL;
    m_name = orig.m_name;
    orig.m_name = NULL;
    std::cout << "Move Constructor " << std::endl;
 }

 SaleItem& SaleItem::operator=(SaleItem&& orig)
{
    m_name = NULL;
    m_name = orig.m_name;
    orig.m_name = NULL;
    std::cout << "Move Assignment======= " << std::endl;
    return *this;
}

int main(int argc,char** argv)
{
    SaleItem obj1;
    SaleItem obj2(obj1);    //拷贝构造函---将类对象作为另一个函数的形参
    obj2.PrintMem();
    
    SaleItem obj3 = obj1;   //拷贝构造函----使用已存在的对象赋值给类新创建的对象!!!
    obj3.PrintMem();

    obj3 = obj1;            //拷贝赋值运算符-----使用已存在的对象赋值给另一个已存在的对象!!!

    SaleItem objMo(std::move(obj1));    //移动构造函数

    SaleItem objAssg;
    objAssg = std::move(obj3);          //移动赋值运算符
    return 0;
}

运算结果如下:

 附加:

 可以参考的博客如下:

C++_拷贝赋值运算符详解_深入浅出_图文并茂_Dancing With Bugs的博客-CSDN博客_拷贝赋值运算符实现

C++中拷贝构造函数与赋值构造函数详解_m0_60150025的博客-CSDN博客_c++ 拷贝构造函数和拷贝赋值函数

移动复制构造函数与移动赋值构造函数 - 李兆龙的博客 - 博客园 (cnblogs.com)

C++11新特性:移动构造函数和移动赋值_简单l的博客-CSDN博客_移动构造函数和移动赋值函数

c++ 之 std::move 原理实现与用法总结_ppipp1109的博客-CSDN博客_stdmove

std::move()与移动构造函数_std::move 构造子类_瘦弱的皮卡丘的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/184839.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Postman前置脚本

位置&#xff1a;作用&#xff1a;调用脚本之前需要执行的代码片段一、产生随机数字生成0-1之间的随机数&#xff0c;包括0&#xff0c;不包括1&#xff1b;var random Math.random();console.log("随机数",random);获取最小值到最大值之前的整数随机数function Get…

2019-ICML-Graph U-Nets

2019-ICML-Graph U-Nets Paper: https://arxiv.org/abs/1905.05178 Code: https://github.com/HongyangGao/Graph-U-Nets 图U-Nets 作者将CNN上的U-Net运用到了图分类上&#xff0c;因为我们主题是图分类&#xff0c;就不对U-Net进行论述了&#xff0c;只对其中的gPool&#…

eureka 读写锁的一点思考

读写锁 读写锁一般实现 读读不互斥 读写互斥 写写互斥 读写锁的好处是&#xff0c;面对读多写多的场景会拥有比较好的表现 一般我们会在读操作加上读锁&#xff0c;写操作加上写锁。但是最近我发现eureka 在使用读写锁的时候是相反的&#xff0c; 也就是说在读操作加上了读锁&…

2023最值得入手的运动耳机是哪款、口碑最好的运动蓝牙耳机推荐

不知道有没有和我一样的小伙伴&#xff0c;在运动时特别喜欢听音乐&#xff0c;每次听到一首合适的音乐&#xff0c;感觉运动起来都更有激情和活力了。所以这时候就需要挑选一款舒适的耳机了。别看市面上各种各样的运动耳机很多&#xff0c;但实际上能真正适合运动的少之又少&a…

oss服务端签名后直传分析与代码实现

文章目录1.简介1.1 普通上传方式1.2 服务端签名后直传3.服务端签名后直传文档3.1 用户向应用服务器请求上传Policy和回调。3.2 应用服务器返回上传Policy和签名给用户。3.3 用户使用Post方法向OSS发送文件上传请求。4.实战开发-后端4.1 pom.xml核心配置4.2 application.yml核心…

Java两大工具库:Commons和Guava(2)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客。值此新春佳节&#xff0c;我给您拜年啦&#xff5e;祝您在新的一年中所求皆所愿&#xff0c;所行皆坦途&#xff0c;展宏“兔”&#xff0c;有钱“兔”&#xff0c;多喜乐&#xff0c;常安宁&#xff01;开发中有一类应…

如何在es中查询null值

文章目录1、背景2、需求3、准备数据3.1 创建mapping3.2 插入数据4、查询 name字段为null的数据5、查询address不存在或值直接为null的数据6、参考链接1、背景 在我们向es中写入数据时&#xff0c;有些时候数据写入到es中的是null&#xff0c;或者没有写入这个字段&#xff0c;…

离散数学与组合数学-08谓词逻辑

文章目录离散数学与组合数学-08谓词逻辑8.1 谓词的引入8.1.1 引入谓词逻辑8.1.2 个体词与谓词8.2 量词的引入8.2.1 量词引入8.2.2 个体域符号化8.2.3 量词真值确定8.3 谓词符号化举例8.3.1 示例一8.3.2 示例二8.3.3 示例三8.3.4 示例四8.4 谓词合式公式8.4.1 四类符号8.4.2 项8…

MySQL运维(一)MySQL中的日志、Mysql主从复制

MySQL运维(一)MySQL中的日志、Mysql主从复制 1、MySQL日志 1.1 错误日志 错误日志是 MySQL 中最重要的日志之一&#xff0c;它记录了当 mysqld 启动和停止时&#xff0c;以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时&#…

Elasticsearch 需要了解的都在这

ES选主过程&#xff1f;其实ES的选主过程其实没有很高深的算法加持&#xff0c;启动过程中对接点的ID进行排序&#xff0c;取ID最大节点作为Master节点&#xff0c;那么如果选出来的主节点中存储的元信息不是最新的怎么办&#xff1f;其实他是分了2个步骤做这件事&#xff0c;先…

react 项目 中使用 Dllplugin 打包优化技巧

目录 0.React和DLLPlugin 前言 使用步骤 结果截图 主要说明 0.React和DLLPlugin React 是一个用于构建用户界面的 JavaScript 库。它由 Facebook 开发&#xff0c;现在由 Facebook 和一个由个人开发者和公司组成的社区维护。React 允许开发人员构建可重用的 UI 组件并有…

“回文子串、最长回文子序列”总结,动态规划再显神通(Java实现)

目录 一、回文子串 1.1、dp定义 1.2、递推公式 1.3、初始化 1.4、遍历顺序 1.5、解题代码 二、最长回文子序列 2.1、dp定义 2.2、递推公式 2.3、初始化 2.4、遍历顺序 2.5、解题代码 一、回文子串 题目描述&#xff1a; 题目来源&#xff1a;647. 回文子串 1.1、dp定…

解决使用copy.deepcopy()拷贝Tensor或model时报错只支持用户显式创建的Tensor问题

模型训练过程中常需边训练边做validation或在训练完的模型需要做测试&#xff0c;通常的做法当然是先创建model实例然后掉用load_state_dict()装载训练出来的权重到model里再调用model.eval()把模型转为测试模式&#xff0c;这样写对于训练完专门做测试时当然是比较合适的&…

ssm学生心理健康测评网的规划与设计

摘 要 1 Abstract 1 1 绪论 1 1.1 课题背景 1 1.2 课题研究现状 1 1.3 初步设计方法与实施方案 2 1.4 本文研究内容 2 2 系统开发环境 4 2.1 JSP技术介绍 4 2.2 B/S模式 4 2.3 MySQL环境配置 5 3 系统分析 6 3.1 系统可行性分析 6 3.1.…

【模糊神经网络】基于模糊神经网络的倒立摆轨迹跟踪控制

临近春节没啥事做&#xff0c;突然想起前两年未完成的模糊神经网络&#xff0c;当时是学了一段时间&#xff0c;但是到最后矩阵求偏导那块始终不对&#xff0c;最后也不了了之了&#xff0c;趁最近有空&#xff0c;想重新回顾回顾&#xff0c;看看会不会产生新的想法。经过不断…

elasticsearch基本操作

elasticsearch基本操作基础两种模式:ik分词器词库拓展索引库操作mapping映射属性typeindexanalyzerproperties索引库的CRUD创建修改查询删除文档操作创建查询修改删除基础 本教程使用es8.6.0与kibana作为测试环境 打开开发工具 ## 1.查看节点信息 GET /_cat/nodes?v ## 2.查…

【JUC并发编程】深入浅出Java并发基石——AQS

【JUC并发编程】深入浅出Java并发基石——AQS 参考资料&#xff1a; RedSpider社区——第十一章 AQS 深入剖析并发之AQS独占锁 1.5w字&#xff0c;30图带你彻底掌握 AQS&#xff01; 深入浅出AbstractQueuedSynchronizer 我画了35张图就是为了让你深入 AQS 动画演示AQS的核心原…

遍历 “可变参数模板” 的模板参数

类模板和函数模板&#xff0c;只能包含固定数量的模板参数&#xff0c;C11支持模板参数可变&#xff0c;那么在不知道模板参数有多少个的情况下&#xff0c;如何遍历模板参数&#xff1f; 目录 一、可变参数模板的声明 二、可变参数模板的遍历 1、递归遍历 2、非递归遍历 …

idea使用DataBase连接数据库 Free MyBatis Tool自动生成 实体类工具使用

DataBase DataBase连接数据库 设置DataSources Host 》IP地址Port 》端口号User 》用户名Password 》密码Database 》连接的数据库 设置驱动 Drives tables 文件夹中即所连接数据库中表 Free MyBatis Tool自动生成 实体类&#xff0c;Mapper &#xff0c;以及mapper.xml 选…

CleanMyMac4.12.3最新版本Mac系统清理工具

CleanMyMac可以为Mac腾出空间&#xff0c;软件已经更新到CleanMyMac X 支持最新版Macos 10.14系统。CleanMyMac具有一系列巧妙的新功能&#xff0c;可让您安全&#xff0c;智能地扫描和清理整个系统&#xff0c;删除大量未使用的文件&#xff0c;减小iPhoto图库的大小&#xff…