博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
EC笔记:第二部分:11:在operator=中处理“自我赋值”
阅读量:5278 次
发布时间:2019-06-14

本文共 2157 字,大约阅读时间需要 7 分钟。

已经一年半没有写过博客了,最近发现学过的知识还是需要整理一下,为知笔记,要开始收费了以前写在为知笔记上笔记也会慢慢的转到博客里。

 

话不多说,进入正题。

 

考虑考虑以下场景:

当某个对象对自身赋值时,会出现什么现象??

例子:

#include <iostream>

class A {

private:

    int *arr;

public:

    A() {

        arr = new int[256];

    }

    ~A() {

        delete arr;

    }

    const A& operator=(const A &other) {

        delete arr;                    //清除原来的值

        arr = new int[256];            //重新分配内存

        std::memcpy(arr, other.arr, 256 * sizeof(int));    //赋值

        return *this;

    }

};

 

 

在这段代码中,类A管理了256个整数的数组,当发生赋值操作时,对象先将自身管理的内存区释放,然后重新分配内存并且赋值(这里可以直接进行内存拷贝,为了演示,做了删除并重新分配操作,假设这里是个vector,想象一下^_^)。这个实现在应对大多数情况是没有问题的。如:

 

int main() {

    A a;

    A b;

    a = b;

}

这样完全没有问题。但是,假设出现以下场景:

int main() {

    A a;

    A &b = a;

 

    //若干操作

 

    a = b;

}

 

a和b表示的是同一个对象,那么在重新分配内存之前,就会将arr(a和b是同一个)指向的内存区域释放。然后在做memcpy的时候程序就会崩溃(引用了已释放的内存区域)。

 

重新对class A的operator=实现:

#include <iostream>

class A {

private:

    int *arr;

public:

    A() {

        arr = new int[256];

    }

    ~A() {

        delete arr;

    }

    const A& operator=(const A &other) {

        if(this == &other)

            return *this;

        delete arr;                    //清除原来的值

        arr = new int[256];            //重新分配内存

        std::memcpy(arr, other.arr, 256 * sizeof(int));    //赋值

        return *this;

    }

};

 

改进后,判断当前如果赋值和被赋值的是同一个对象,就直接返回,可以避免释放掉同一块内存。

 

这段代码虽然可以避免赋值上的问题,但是存在"异常安全性"的问题:试想,假设在new的时候抛出了一个异常(假设内存不足),那么,a在处理异常时,arr的状态就已经发生变化了。

 

另外,书中介绍了另一种避免赋值的时候释放掉有用内存的代码:

#include <iostream>

class A {

private:

    int *arr;

public:

    A() {

        arr = new int[256];

    }

    ~A() {

        delete arr;

    }

    const A& operator=(const A &other) {

        int *old_arr = arr;

        arr = new int[256];

        std::memcpy(arr, other.arr, 256 * sizeof(int));

        delete old_arr;

        return *this;

    }

};

 

这段代码中,先对原有的arr做一个备份,然后使用other对新分配的内存进行更新,最后释放掉原来arr指向的内存区域。

即使没有"证同测试",这段代码也能正常工作,因为释放动作在赋值动作之后,这是后就真的存在两个副本了(如果*this和other指向不同的值,就是3个副本)。但是,这段代码显然在抛开"异常安全性"后在效率上比上面那段代码的效率低(即使两个对象指向同一内存,也要从新分配内存,并重新赋值)。所以,如果关心效率的话,应该在最前面增加"证同测试"。如下:

#include <iostream>

class A {

private:

    int *arr;

public:

    A() {

        arr = new int[256];

    }

    ~A() {

        delete arr;

    }

    const A& operator=(const A &other) {

        if (this==&other)

            return *this;

        int *old_arr = arr;

        arr = new int[256];

        std::memcpy(arr, other.arr, 256 * sizeof(int));

        delete old_arr;

        return *this;

    }

};

 

至此,一份"异常安全的"且"效率优秀的"operator=操作符就完成了

 

请记住:

  1. 确保operator=有良好的行为。
  2. 当某个函数要操作同类对象或者多个继承自同一类对象时,不仅要考虑每个对象不同时的处理,还要考虑当某些对象是同一个对象的处理,确保正确性。

转载于:https://www.cnblogs.com/SkyFireITDIY/p/6201174.html

你可能感兴趣的文章
初识XML Database
查看>>
一种解决新版本API完全兼容老版本API的方法
查看>>
《数据挖掘导论》 - 读书笔记(1) - 概况 | 目录 [2016-8-8]
查看>>
Kattis - String Matching(kmp)
查看>>
Android中活动的最佳实践(如何很快的看懂别人的代码activity)
查看>>
this指针
查看>>
【原】PHPExcel相关
查看>>
Dede没见过的漏洞
查看>>
Http状态码详解
查看>>
VMware下重装CentOS
查看>>
通用权限管理平台--综合查询插件
查看>>
Eclipse解决方案之"Eclipse is running in a JRE, but a JDK is required"
查看>>
Struts:文件上传下载
查看>>
【转】【金蝶K3Cloud】 分页账表
查看>>
HDU ACM【1001~1004】
查看>>
【原】Win7 host 与 virtualbox ubuntu guest 相同ping通
查看>>
jQuery的$.ajax方法响应数据类型有哪几种?本质上原生ajax响应数据格式有哪几种,分别对应哪个属性?...
查看>>
第8章 IO类
查看>>
Insert data from excel to database
查看>>
用户控件赋值
查看>>