c++之移动构造函数或者移动赋值运算符的作用详解

 更新时间:2025年03月04日 09:47:09   作者:_DCG_  
文章介绍了移动构造函数和移动赋值运算符的核心作用,它们通过资源管理权转移的方式实现对象的构造,减少内存拷贝的开销,移动构造函数的参数一定是一个右值引用

原理介绍

前面的文章中有的涉及到了移动构造函数或者移动赋值运算符,对于它们的形式有了一定的了解,但是对他们的核心作用以及为什么要引入这两个东东,很多朋友还是一知半解。本文就是来解决这个问题的。

要理解这个问题绕不开右值引用,c++11之前的 版本中只有拷贝构造函数,而拷贝构造函数是一般会深拷贝,即会创建两个完全一样的对象,包括指针指向的区域都会进行重新申请内存和拷贝。这种情况下如果对象是一个大数组或占用资源多的对象,就会产生很大的内存拷贝开销。那么如何解决这个问题呢?

c+11版本引入了右值引用、移动语义来解决这个问题。这里先说结论:通过移动构造函数或移动赋值运算符产生的对象与元对象会产生一个资源的转移。举个形象的例子:小明手里有个篮球,小王手里没有篮球,以前的拷贝构造函数或者拷贝赋值运算符重载的结果是小王会按照小明手里的篮球重新买一个;而移动构造函数和移动赋值运算符重载实现则更像是小王把小明手里的篮球放到自己手里,而小明手里没有了篮球。

从上面的例子可以看出移动构造函数或移动赋值运算符的作用就是通过资源管理权转移的方式实现对象的构造,使得可以减少内存拷贝的开销。

移动构造函数的的参数一定是一个右值引用。

下面是一个给出一个移动构造函数的典型的例子:

class MyClass
{
    std::string str;  //一个类成员
    int* ptr;  //一个指针成员

    public: 
        A(){}
        A(MyClass && a)::str(std::move(a.str))
        {
            
        }

        A operator=(MyClass&& a)  //移动赋值运算符重载
        {
            if(this != &a)
            {
                str = std:move(a.str); //这里因为str::string类已经实现了移动构造赋值运算符,std::string作为一个类已经支持了这个,所以可以这样做,如果是
                ptr = a.ptr;  //需要自己去切换指针所指向的区域
                a.ptr = nullptr;  
            }
        }

}

注意事项

  1. 一个类的移动构造函数或移动赋值运算符的实现是由类自己实现的
  2. 如果要使用移动构造函数或者移动赋值运算符,那么用户必须显式的定义移动构造函数和移动赋值运算符的重载
  3. 一些c++标准库中提供的类很多都已经实现了移动构造函数和移动赋值运算符的重载,例如std::string、stl容器类、智能指针(std::shared_ptr<T>、std::unique_ptr<T>)等
  4. 用户自己定义类在有需要的情况下需要在自定义的类中实现移动构造函数和移动赋值运算符重载。
  5. 移动构造函数或移动赋值运算符重载实现基于右值引用,一定是以右值引用作为参数的

思考

移动构造函数本质是资源管理权的转移,那如果跟std::shared_ptr<T>会发生什么?

  • 请看下面的代码:
class MyClass
{
    public:
        A(){
            std::cout<<"A的构造函数"<<std::endl;
        }
        ~A(){
            std::cout<<"A的析构函数"<<std::endl;
        }   
}

class Container
{
    private:
        std::shared_ptr<MyClass> ptr;
    public:
        Container(Container&& container):ptr(std::move(container.ptr))
        {
            std::cout<<"移动构造函数"<<std::endl;
        }
        Container operator=(Container&& container)
        {
            if(this != &container)  //这里不能少
            {        
                ptr = std::move(container.ptr); //这里也可以,因为std::shared_ptr内部实习拿了移动赋值运算符
            }    
        }
}

shared_ptr 的移动操作:

  • 转移资源所有权
  • 源指针置空
  • 保持引用计数不变
  • 是线程安全和异常安全的

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 基于Qt实现日志打印系统

    基于Qt实现日志打印系统

    这篇文章主要为大家详细介绍了如何利用Qt开发一个日志打印系统,可以实现打印日志按日期、大小保存,过期删除,窗口实时显示日志,网络传输日志远程调试,需要的可以参考下
    2023-12-12
  • C++赋值运算符

    C++赋值运算符

    这篇文章主要介绍了C++赋值运算符,C++当中允许类对象赋值,这是通过默认的重载赋值运算符实现的,下面我们就来介绍介绍该内容吧,,需要的朋友可以参考一下
    2022-01-01
  • C语言实现顺序表的基本操作指南(注释很详细)

    C语言实现顺序表的基本操作指南(注释很详细)

    线性表是最简单的数据结构,而顺序表又是最简单的线性表,其基本思想是用一段地址连续的储存单元依次存储线性表的数据元素,下面这篇文章主要给大家介绍了关于C语言实现顺序表的基本操作,需要的朋友可以参考下
    2021-10-10
  • C语言字符串函数,字符函数,内存函数使用及模拟实现

    C语言字符串函数,字符函数,内存函数使用及模拟实现

    这篇文章主要介绍了C语言字符串函数,字符函数,内存函数使用及模拟实现,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • C++实现 vector 的四则运算

    C++实现 vector 的四则运算

    本文给大家介绍的是在C++中实现高效的vector四则运算的方法的相关资料,需要的朋友可以参考下
    2016-07-07
  • C++中memcpy和memmove的区别总结

    C++中memcpy和memmove的区别总结

    这篇文章主要介绍了C++中memcpy和memmove的区别总结,这个问题经常出现在C++的面试题目中,需要的朋友可以参考下
    2014-10-10
  • C++中POCO库的安装与基础知识介绍(Windwos和Linux)

    C++中POCO库的安装与基础知识介绍(Windwos和Linux)

    这篇文章主要为大家介绍了C++ POCO库的简单介绍、下载以及安装方式、简单代码示例,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2023-05-05
  • C++前置声明的方式与说明介绍

    C++前置声明的方式与说明介绍

    本文给大家介绍c++前置声明的方式与说明,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2026-03-03
  • C语言实现手写Map(全功能)的示例代码

    C语言实现手写Map(全功能)的示例代码

    这篇文章主要为大家详细介绍了如何利用C语言实现手写Map(全功能),文中的示例代码讲解详细,对我们学习C语言有一定帮助,需要的可以参考一下
    2022-08-08
  • C++指向函数的指针实例解析

    C++指向函数的指针实例解析

    这篇文章主要介绍了C++指向函数的指针,需要的朋友可以参考下
    2014-07-07

最新评论