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

发布时间:2026/7/31 0:37:27

C++中拷贝构造函数、拷贝赋值运算符、析构函数、移动构造函数、移动赋值运算符(三/五法则) 1、介绍三五法则是针对C中类的成员和类对象的操作函数。三法则是指拷贝构造函数、拷贝赋值运算符、析构函数。五法则是在三法则的基础上增加了移动构造函数、移动赋值运算符。2、拷贝构造函数定义如果构造函数的第一个参数是自身类类型的引用且任何额外的参数都有默认值则该构造函数时拷贝构造函数。如果没有为类定义拷贝构造函数则编译器会默认生成拷贝构造函数。用途定义已存在的类对象去初始化该类的新对象的成员初始化过程。egclass Foo { public: Foo(); //默认构造函数 Foo(const Foo); //拷贝构造函数 //..... }拷贝初始化和直接初始化差异string dots(9,.); //直接初始化 string s(dots); //直接初始化 string s2 dots; //拷贝初始化 stirng null_book hello world; //拷贝初始化 string ninesstring(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、移动构造函数、移动赋值运算符简单的来说就是将一个原先对象的管理权移动到另一个新对象上。原先被对象则不可再用因为管理权已移动到新的对象上移动构造函数和移动赋值运算符的优点是不用深拷贝数据直接将原先的对象数据移动到新的对象上提高了效率。需要定义移动构造函数的场景自定义的数据如果要使用移动变量内存的方式来获取数据则需要定义移动构造函数。因为自定义数据不支持移动需要自定定义移动构造函数。标准库容器、string和shared_ptr类即支持移动也支持拷贝。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_n110; int m_n2 1; int *m_name NULL; }; /*SaleItem::SaleItem(const SaleItem orig) { m_n1 orig.m_n12; 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(const SaleItem orig) : m_n1(orig.m_n1), m_n2(orig.m_n2), m_name(orig.m_name ? new int(*orig.m_name) : nullptr) { std::cout Copy Constructor std::endl; } SaleItem SaleItem::operator(const SaleItem orig) { if (this ! orig) { m_n1 orig.m_n1; m_n2 orig.m_n2; int* newName orig.m_name ? new int(*orig.m_name) : nullptr; delete m_name; m_name newName; } std::cout Copy Assignment std::endl; return *this; } /* SaleItem::SaleItem(SaleItem orig) { if(m_name ! NULL) { delete m_name; m_name NULL; } m_name orig.m_name; orig.m_name NULL; std::cout Move Constructor std::endl; }*/ SaleItem::SaleItem(SaleItem orig) noexcept : m_n1(orig.m_n1), m_n2(orig.m_n2), m_name(orig.m_name) { orig.m_name nullptr; std::cout Move Constructor std::endl; } SaleItem SaleItem::operator(SaleItem orig) { if (this ! orig) { delete m_name; m_n1 orig.m_n1; m_n2 orig.m_n2; m_name orig.m_name; orig.m_name nullptr; } 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)C11新特性移动构造函数和移动赋值_简单l的博客-CSDN博客_移动构造函数和移动赋值函数c 之 std::move 原理实现与用法总结_ppipp1109的博客-CSDN博客_stdmovestd::move()与移动构造函数_std::move 构造子类_瘦弱的皮卡丘的博客-CSDN博客

相关新闻