首页 > 编程语言 >C++三五法则

C++三五法则

时间:2024-10-31 17:44:10浏览次数:1  
标签:法则 int 三五 C++ swap 显式 const pi 赋值

 若类中有资源在构造函数中创建,并在析构函数中释放,此时需要显式定义拷贝构造赋值析构等操作,若在程序没有显示声明并定义时,会被隐式生成,对于不包含联合体的类,隐式生成的拷贝构造函数和赋值运算在执行时,会按成员对象依次复制,隐式生成的析构函数为空

如下面的类T管理资源int*

class T{
public:
    T(int i){
        pi= new int(i);
        // pi= std::make_shared<int>(i);
    }
private:
    int* pi;
    // std::shared_ptr<int> pi;
};

1. 显式定义拷贝构造函数的情况

T(const T& t){
    // this->pi= new int(*t.pi);
    this->pi= new int; // 申请内存,并复制对象
    *this->pi= *t.pi;
}

2. 显式重载赋值运算符的情况

实现赋值运算时,应考虑的问题:

  • 自检查
    防止自赋值
  • 删除自身资源
    若在new时抛出异常,则会无法恢复原状态,可用临时变量或后面介绍的copy-and-swap解决
  • 复制资源
    代码冗余,和拷贝构造中做一样的操作
T& operator= (const T& t){
    if(this!=&t){
        this->pi= new int;
        *this->pi= *t.pi;
        return *this;
    }
}

3. 显式定义析构函数

~T(){
    delete pi; // 释放资源
}

不可复制的资源

如文件句柄和互斥量等是不可复制的,此时拷贝构造函数赋值运算需要特殊处理

  • 定义在private
    private:
      T(const T& t);
      T& operator=(const T& t);
    
  • 用C++11中的delete实现
    T(const T& t) = delete;
    T& operator=(const T& t) = delete;
    

C++11五法则

C++11中引入了右值引用,多了移动语义,所以相应地新增了移动构造移动赋值运算

T(T&&) noexcept= default;
T& operator=(T&&)noexcept= default;

建议:

  1. 尽量不要在一个类中管理多个资源,否则日后会知道什么是痛苦
  2. 若要显式定义析构函数、复制构造函数或赋值运算符中的一个,则也应显式定义另外两个
  3. 大多数情况下都没必要自己实现管理资源的类,std中基本上都有实现,只要避免原始指针,”五法则”基本上也就用不到

copy-and-swap

 任何资源管理类,都需要遵循三法则,其中,拷贝构造和析构函数的实现相对简单,赋值运算符重载会复杂许多

 copy-and-swap是实现赋值运算符重载的完美解决方案,既能避免代码冗余,又可以提供强异常安全保证
大致思路:先用拷贝构造创建一个副本,再利用swap交换数据成员,在作用域结束时,副本会自动调用析构函数

在实现赋值运算时,使用copy-and-swap解决上述问题

friend void swap(T& src, T& dest){
    std::swap(src.str, src.str); // <algorithm>
}
T& operator=(T t){
    swap(*this, t);
    return *this;
}

标签:法则,int,三五,C++,swap,显式,const,pi,赋值
From: https://www.cnblogs.com/sgqmax/p/18518520

相关文章

  • C++泛型一:模板
    数据类型给程序设计带来的困扰及解决方案intmaxt(int,int);doublemaxt(double,double);若有一种占位符T,能够代替类型,便可以简化代码的冗余编写Tmaxt(T,T);C++模板模板声明如下template<typenameT1,...>template是C++的模板声明关键字,尖括号内为模板参数列表typ......
  • C++范型二:右值引用
    为类所设计的转移语义拷贝构造函数和转移语义赋值运算符使得临时对象有了将资源直接转移给另一个对象的能力,从而避免了内存分配、资源拷贝等深拷贝过程作为注重效率的模板,当然要引入右值引用及相关技术,其成果就是参数完美转发模板右值引用左值和右值左值代表一块存储空间,可以......
  • C++范型三:数据类型表
    类的数据类型成员C++中,在类模板中用typedef定义的数据类型称为内嵌类型nestedtypetemplate<typenameT>classMyTraits{public:typedefTmytype;};如下,使用内嵌类型在类外定义变量typenameMyTraits<int>::mytypen;可知,类外引用类模板的公有类型成员和引用类静......
  • C/C++中的指针详解(重点)
    指针是C和C++中一个重要且强大的特性。它们允许程序员直接访问和操作内存,提供了灵活的内存管理和高效的数据结构实现。对一个变量取*操作其实就是取到这个变量的地址,然后再对取到的变量进行读写等操作以下是对指针的详细介绍:1.什么是指针指针是一个变量,它存储另一个变量的......
  • 【C++】01-C++ 程序的生成过程
    概要:该篇文章以MSCV为例,简要介绍了C++程序的生成过程。1.生成工具MSVC,全称MicrosoftVisualC++,是由微软开发的用于生成C++程序的工具集,包括C++预处理器、编译器、链接器和其他生成工具。2.生成过程2.1预处理(Preprocess)预处理由预处理器(Preprocessor)......
  • C++ halcon判断图像是否为空
    使用CountObj函数首先,可以使用CountObj函数来检查当前图像是否为空。如果图像为空,则返回的计数为0;否则,返回的计数大于0。示例代码如下:cppCopyCode HTuplehNum;HalconCpp::CountObj(m_hCurrentImg,&hNum);if(hNum==0){qDebug()<<"传入图像为空!";}else{qDebu......
  • 【C++】红黑树的插入与删除
    第一篇数据结构学习之红黑树的实现系列文章目录前言一、红黑树的基本概念二、参考视频链接三、代码实现1.定义节点类2.旋转方法3.红黑树插入操作4.红黑树删除操作四,总体代码总结系列文章目录第一篇数据结构学习之红黑树的实现前言红黑树是一种平衡二叉搜索树,在......
  • C++——写一函数,将一个3x3的整型矩阵转置。用指针或引用方法处理。
    没注释的源代码#include<iostream>usingnamespacestd;voidmove(int*p);intmain(){  inta[3][3],*p;  cout<<"pleaseinputmatrix:"<<endl;  for(inti=0;i<3;i++)  {    for(intj=0;j<3;j++)    {     ......
  • C++——将一个5x5的矩阵中最大的元素放在中心,4个角分别放4个最小的元素(按从左到右、
    没注释的源代码#include<iostream>#include<stdio.h>#include<string.h>usingnamespacestd;voidtransform(int*arry,intcol_row);intmain(){   intarry[5][5];   cout<<"Pleaseentera5x5matrix:"<<endl;   for(......
  • C++(std::to_string())
    目录1.函数定义2.示例代码3.内部实现机制4.注意事项5.应用场景6.使用std::ostringstream控制精度的示例7.总结std::to_string()是C++11引入的一个标准库函数,用于将基本数据类型(如整数、浮点数等)转换为对应的字符串格式。这个函数属于<string>头文件,因此使用时需......