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

话不多说,进入正题。

考虑考虑以下场景:

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

例子:

#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

EC笔记:第二部分:11:在operator=中处理“自我赋值”相关推荐

  1. Effective C++ 11 在operator=中处理“自我赋值” 笔记

    "自我赋值"发生在对象被赋值给自己时: 1 class Widget {...}; 2 Widget w; 3 ... 4 w = w; //赋值给自己 这看起来有点愚蠢,但它合法 ...

  2. 条款11 在operator=中处理“自我赋值”

    "自我赋值"发生在对象被赋值给自己时: 1 class Widget {...}; 2 Widget w; 3 ... 4 w = w; //赋值给自己 这看起来有点愚蠢,但它合法 ...

  3. 条款11:在operator=中处理“自我赋值”

    什么是自我赋值,就是 v = v 这种类型的语句,也许很多人都会说鄙视这种写法,但是如下的写法会不会出现呢? 比如:a[i] = a[j];      // 不巧的是i可能和j相等 *px = *py ...

  4. Effective C++ 条款11:在operator=中处理自我赋值

    "自我赋值"发生在对象被赋值给自己时: class Widget { ... }; Widget w; ... w = w; // 赋值给自己 a[i] = a[j]; // 潜在 ...

  5. C++尽量在operater=中处理“自我赋值”

    operater=中处理"自我赋值 下面的operator=实现是一份不安全的实现,在自赋值时会出现问题: 1.在开头添加"证同测试" c++ 2.通过确保异常安全来获得 ...

  6. Qt|Linux工作笔记-第二种方式读取Linux中top命令(直接读取,非重定向)

    第一种方式的链接如下: https://mp.csdn.net/postedit/84067805 第一种方式是重定向到文件,然后读取, 第二种方式不重定向到文件,直接读取! 利用QProcess的特 ...

  7. AE学习笔记——第二章:AE图层中的图层用法及基本操作

    目录 (1)剪辑和拆分图层 A:剪辑图层 B:拆分图层 C:时间指示线的其它操作 (2)在图层预览面板中剪辑图层 (3)图层属性与标签色 (4)图层的对齐和分布 A:对齐 B:分布 (5)时间轴面板部 ...

  8. 《数据库设计入门经典》读书笔记——第二章:工作场所中的数据库建模

    感觉这章讲的技术点很少,我就不想写了,这章就跳过了. 转载于:https://www.cnblogs.com/tuhooo/p/8468760.html

  9. 《Go语言圣经》学习笔记 第二章 程序结构

    Go语言圣经学习笔记 第二章 程序结构 目录 命名 声明 变量 赋值 类型 包和文件 作用域 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. Go语言小白学习笔记,几乎是书上的内 ...

最新文章

  1. 【Angular4】英雄指南demo
  2. SecureCrt使用技巧
  3. Provisioning profile XXXX can't be found
  4. boost::hana::reverse用法的测试程序
  5. 记住北京历史上的灾难
  6. Pipelines - .NET中的新IO API指引(一)
  7. LeetCode 388. 文件的最长绝对路径(不用栈,前缀和)
  8. 发布一个免费漂亮的仿Outlook风格、支持换肤的通用界面框架
  9. php 取出多重数组中的一列_PHP提取多维数组指定一列的方法大全
  10. NumPy 1.19.3 发布,Python 科学计算包
  11. pe常用软件_装机不求人之打造自己的全功能PE系统维护优盘
  12. telnet无法访问
  13. java:eclipse:windows开发环境log4j系统找不到指定的路径
  14. 著名的软件项目开发和生命周期管理软件MKS.Code.Integrity.Enterprise.Edition.v12
  15. matlab 点云曲率,点云数据的主曲率和主方向估计方法
  16. 面试必备(背)-Linux八股文系列!
  17. 字模C语言入门,PCtoLCD2002完美版取字模工具软件及其步骤教程
  18. 软件项目经理应具备的素质和条件_软件项目经理的素质能力要求
  19. Swift中数组字典和plist文件的转换
  20. 相遇在这茫茫的网海里。你在天涯,我在海角

热门文章

  1. android attrs获取_Android 常用侧滑栏实现
  2. nginx重新加载php,如何使用nginx启动、停止和重新加载
  3. UCINET 社会网络分析工具
  4. 火箭轨道计算属于什么计算机技术,2018年计算机二级高级Office每日一练 2月27日...
  5. jenkins 手动执行_我常用的SpringBoot+Jenkins自动化部署技巧,贼好用,推荐给大家...
  6. mysql关联查询去重_MySQL外键和高级查询(连接查询、联合查询、子查询、去重查询)...
  7. php文件用什么浏览,什么是PHP文件 php文件用什么打开
  8. mysql 查数据 default无效_导入mysql数据的时候提示Field * doesn't have a default value解决方法...
  9. yaml数组解析_yaml格式详解
  10. 数据仓库--基本概念