5.赋值运算符函数

1.返回值类型为自身对象引用
原因:减少一次拷贝构造函数,引用可以连续赋值。
2.参数为常量引用
原因:const不改变原来对象的值,引用避免了拷贝构造函数。当参数不是引用而是实例时,从形参到实参会调用一次拷贝构造函数。

A& operator=(const A obj){
    ...
}

int main(){
    A a;
    A b;
    b=a;//A obj=a;调用拷贝构造函数
}

3.判断当前对象与参数是否为同一地址
原因:保证自赋值的安全,当传入参数和当前参数是同一实例时,若释放了当前对象的内存则参数内存也将释放,找不到赋值内容。
4.在分配新内存之前释放内存
原因:在分配新内存之前没有释放之前的内存则会出现内存泄露。
int *a=new int[10];
delete [] a;/dele

Mystring& operator=(const Mystring &ptr)
    {
        if(this==&ptr)
            return *this;
        delete m_pData;
        m_pData=NULL;
        m_pData=new string;
        *m_pData=*ptr.m_pData;
        return *this;
    }

5.异常安全性
释放自身实例内存后,若此时内存不足则分配新内存时会出现异常
解决办法:先创建临时实例,再交换临时实例和自身实例。

Mystring& operator=(const Mystring &ptr)
    {
        if(this!=&ptr){
            Mystring strtemp(ptr);//创建临时实例

            char *pTemp=strtemp.m_pData;//交换自身实例和临时实例
            strtemp.m_pData=m_pData;
            m_pData=pTemp;
        }
        return *this;
    }
### C++ 拷贝赋值运算符函数的实现与用法 #### 什么是拷贝赋值运算符? 拷贝赋值运算符是一种特殊的成员函数,用于处理对象之间的赋值操作。它允许开发者自定义当一个对象被赋予另一个同类型的对象时的行为。通常情况下,编译器会提供默认的拷贝赋值运算符,但如果类中有动态分配内存或其他需要特殊处理的情况,则可能需要手动定义该运算符。 形式化地表示,拷贝赋值运算符是一个重载的操作符 `=` 函数,其签名如下: ```cpp class MyClass { public: MyClass& operator=(const MyClass&); }; ``` 其中,`MyClass&` 表示返回当前对象的引用,而 `const MyClass&` 是右操作数的常量引用[^2]。 --- #### 默认行为 如果没有显式定义拷贝赋值运算符,编译器会生成一个默认版本。这个默认版本执行的是逐成员复制(member-wise copy),即将源对象中的每个非静态数据成员逐一复制到目标对象中。然而,在某些场景下,默认行为可能导致问题,例如涉及指针或动态资源管理时可能会引发浅拷贝问题[^1]。 --- #### 手动实现拷贝赋值运算符 为了防止潜在的风险并确保正确性,可以手动实现拷贝赋值运算符。以下是其实现的关键点: 1. **检查自赋值** 需要先判断左操作数和右操作数是否相同,如果相同则无需任何操作以避免不必要的开销甚至错误。 2. **释放现有资源** 如果当前对象已经持有某种资源(如动态分配的内存),应先安全地释放这些资源,然后再进行新资源的分配。 3. **复制新资源** 将右侧对象的数据完全复制过来,包括深拷贝必要的部分。 下面给出一个完整的例子来说明如何实现拷贝赋值运算符: ```cpp #include <iostream> using namespace std; class MyClass { private: int* data; public: // 构造函数 explicit MyClass(int value = 0) : data(new int(value)) {} // 拷贝构造函数 MyClass(const MyClass& other) : data(new int(*other.data)) {} // 拷贝赋值运算符 MyClass& operator=(const MyClass& other) { if (this != &other) { // 自赋值检测 delete data; // 释放原有资源 data = new int(*(other.data)); // 复制新的资源 } return *this; // 返回当前对象的引用 } ~MyClass() { delete data; // 销毁时清理资源 } void display() const { cout << "Value: " << *data << endl; } }; int main() { MyClass obj1(42); MyClass obj2; obj2 = obj1; // 调用了拷贝赋值运算符 obj1.display(); // 输出 Value: 42 obj2.display(); // 输出 Value: 42 return 0; } ``` 在这个例子中,我们展示了如何通过拷贝赋值运算符完成两个对象之间深层次的内容传递,并且避免了常见的陷阱——如重复释放同一块内存等问题。 --- #### 特殊情况:禁用拷贝赋值运算符 有时出于设计考虑,希望阻止某个类的对象被赋值给其他对象。可以通过将拷贝赋值运算符声明为删除状态 (`=delete`) 来达到此目的。例如: ```cpp class NonCopyable { public: NonCopyable() {} NonCopyable(const NonCopyable&) = delete; // 删除拷贝构造函数 NonCopyable& operator=(const NonCopyable&) = delete; // 删除拷贝赋值运算符 }; ``` 这样做的典型应用场景是在单例模式或者线程池等不允许随意复制实例的情况下[^3]。 --- #### 总结 - 拷贝赋值运算符的主要作用在于控制对象间的赋值过程,尤其是在存在动态资源管理需求的时候显得尤为重要。 - 编写时需特别关注三个要点:自赋值检查、旧资源释放以及新资源创建。 - 当不需要支持赋值功能时,可通过`=delete`语法将其禁用掉。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值