移动构造函数、移动赋值运算符 和 拷贝构造函数、拷贝赋值运算符的区别

本文介绍了C++11引入的移动构造函数和移动赋值运算符,这两种机制减少了对象拷贝的开销,提高了性能。移动构造函数通过接管传入对象的资源来避免深拷贝,而移动赋值运算符同样实现了高效资源转移。然而,需要注意的是,当涉及到指针时,移动操作可能导致野指针问题,因此在移动后需要将原始对象的指针置空以防止内存泄漏。移动语义在处理大对象和临时对象时特别有用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

移动构造函数和拷贝构造函数的

移动构造函数移动赋值运算符 是C++11新引进的特性。

在C++11以前,对象的拷贝主要由三个函数控制: 拷贝构造函数拷贝赋值运算符析构函数 。在C++11引入了 移动构造函数移动赋值运算符 两个函数。

    A(A& exp)//拷贝构造函数
    {
        if(exp.array!=nullptr)
        {
            int len = strlen(exp.array);
            array = new char[len+1];
            strcpy(array,exp.array);
        }
    }
    A(A&& exp)//移动构造函数
    {
        if(exp.array!=nullptr)
        {
            array = exp.array;
            exp.array = nullptr;
        }
    }

从上可以看出,移动构造函数的传入参数是右值引用,由 && 标出。对于拷贝构造函数,首先会对传入的对象进行一次深拷贝,然后再传给新对象,这样就会产生一次拷贝开销。而对于移动构造函数,首先会把传入对象的地址空间接管,然后将内部所有指针设置为nullptr ,并在原地址上对新对象进行构造,这样就不会产生额外的拷贝开销。

注意: 在传入参数为指针的情况下,因为移动构造函数进行的是浅拷贝,因此在拷贝之后就会有两个指向同一地址空间的指针,在这种情况下,原对象析构之后就会释放掉指针指向的地址空间,这将导致新对象的指针成为野指针,从而引发错误。所以在进行拷贝之后需要将研对象的指针置空,这样在原对象析构的时候就不会释放掉指针指向的地址空间。

移动赋值运算符和拷贝赋值运算符

与移动拷贝函数类似,移动赋值运算符的参数也是一个右值引用,在完成移动操作之后便会被销毁。

    A& operator=(A& exp)//拷贝赋值运算符
    {
        if(this != &exp)
        {
            free();
            if(exp.array!=nullptr)
        	{
            	int len = strlen(exp.array);
            	array = new char[len+1];
            	strcpy(array,exp.array);
        	}
        }
        return *this;
    }
    A& operator=(A&& exp)//移动赋值运算符
    {
        if(this!=&exp)
        {
            free();
            array = exp.array;
            exp.array = nullptr;
        }
        return *this;
    }

移动语义的出现使得大对象可以避免频繁拷贝造成的性能下降,特别是对于临时对象,移动语义是传递他们的最佳方式!

### C++移动构造函数移动赋值运算符 #### 定义与作用 在现代C++中,为了提高资源管理效率并减少不必要的深拷贝操作,引入了移动语义。这主要通过两个成员函数来实现:移动构造函数移动赋值运算符。 - **移动构造函数**用于当创建新对象时接收另一个临时对象作为源,并直接接管其拥有的资源而不做深层复制。这样可以显著提升性能,尤其是在处理大型数据结构或动态分配内存的情况下[^1]。 - **移动赋值运算符**则是在已有对象上执行相同的操作——即从右侧表达式的右值那里转移资源给左侧的目标实例;同样地,这也避免了昂贵的数据副本过程[^3]。 这两个特性共同构成了所谓的“五法则”,意味着如果自定义了一个类,则应该考虑提供完整的五个特殊成员函数(包括默认构造函数),以确保正确的行为模式[^2]。 #### 使用方法 下面展示如何声明以及简单实现这两种机制: 对于一个简单的字符串容器类 `StringContainer` 来说, ```cpp class StringContainer { private: char* data; public: // 构造函数其他常规功能... // 移动构造函数 StringContainer(StringContainer&& other) noexcept : data(nullptr) { swap(data, other.data); std::cout << "Move constructor called." << std::endl; } // 移动赋值运算符 StringContainer& operator=(StringContainer&& other) noexcept { if (this != &other) { delete[] data; // 清理当前持有的资源 // 接管其他对象的资源 swap(data, other.data); std::cout << "Move assignment operator called." << std::endl; } return *this; } ~StringContainer() { delete[] data; } }; ``` 上述代码片段展示了如何安全有效地利用移动语义优化程序性能。注意,在这里使用了标准库中的 `swap()` 函数来进行资源交换,这是一种常见的做法,有助于简化逻辑并防止潜在的风险[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值