EC笔记:第二部分:11:在operator=中处理“自我赋值”
已经一年半没有写过博客了,最近发现学过的知识还是需要整理一下,为知笔记,要开始收费了以前写在为知笔记上笔记也会慢慢的转到博客里。
话不多说,进入正题。
考虑考虑以下场景:
当某个对象对自身赋值时,会出现什么现象??
例子:
#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=操作符就完成了
请记住:
- 确保operator=有良好的行为。
- 当某个函数要操作同类对象或者多个继承自同一类对象时,不仅要考虑每个对象不同时的处理,还要考虑当某些对象是同一个对象的处理,确保正确性。
转载于:https://www.cnblogs.com/SkyFireITDIY/p/6201174.html
EC笔记:第二部分:11:在operator=中处理“自我赋值”相关推荐
- Effective C++ 11 在operator=中处理“自我赋值” 笔记
"自我赋值"发生在对象被赋值给自己时: 1 class Widget {...}; 2 Widget w; 3 ... 4 w = w; //赋值给自己 这看起来有点愚蠢,但它合法 ...
- 条款11 在operator=中处理“自我赋值”
"自我赋值"发生在对象被赋值给自己时: 1 class Widget {...}; 2 Widget w; 3 ... 4 w = w; //赋值给自己 这看起来有点愚蠢,但它合法 ...
- 条款11:在operator=中处理“自我赋值”
什么是自我赋值,就是 v = v 这种类型的语句,也许很多人都会说鄙视这种写法,但是如下的写法会不会出现呢? 比如:a[i] = a[j]; // 不巧的是i可能和j相等 *px = *py ...
- Effective C++ 条款11:在operator=中处理自我赋值
"自我赋值"发生在对象被赋值给自己时: class Widget { ... }; Widget w; ... w = w; // 赋值给自己 a[i] = a[j]; // 潜在 ...
- C++尽量在operater=中处理“自我赋值”
operater=中处理"自我赋值 下面的operator=实现是一份不安全的实现,在自赋值时会出现问题: 1.在开头添加"证同测试" c++ 2.通过确保异常安全来获得 ...
- Qt|Linux工作笔记-第二种方式读取Linux中top命令(直接读取,非重定向)
第一种方式的链接如下: https://mp.csdn.net/postedit/84067805 第一种方式是重定向到文件,然后读取, 第二种方式不重定向到文件,直接读取! 利用QProcess的特 ...
- AE学习笔记——第二章:AE图层中的图层用法及基本操作
目录 (1)剪辑和拆分图层 A:剪辑图层 B:拆分图层 C:时间指示线的其它操作 (2)在图层预览面板中剪辑图层 (3)图层属性与标签色 (4)图层的对齐和分布 A:对齐 B:分布 (5)时间轴面板部 ...
- 《数据库设计入门经典》读书笔记——第二章:工作场所中的数据库建模
感觉这章讲的技术点很少,我就不想写了,这章就跳过了. 转载于:https://www.cnblogs.com/tuhooo/p/8468760.html
- 《Go语言圣经》学习笔记 第二章 程序结构
Go语言圣经学习笔记 第二章 程序结构 目录 命名 声明 变量 赋值 类型 包和文件 作用域 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. Go语言小白学习笔记,几乎是书上的内 ...
最新文章
- 【Angular4】英雄指南demo
- SecureCrt使用技巧
- Provisioning profile XXXX can't be found
- boost::hana::reverse用法的测试程序
- 记住北京历史上的灾难
- Pipelines - .NET中的新IO API指引(一)
- LeetCode 388. 文件的最长绝对路径(不用栈,前缀和)
- 发布一个免费漂亮的仿Outlook风格、支持换肤的通用界面框架
- php 取出多重数组中的一列_PHP提取多维数组指定一列的方法大全
- NumPy 1.19.3 发布,Python 科学计算包
- pe常用软件_装机不求人之打造自己的全功能PE系统维护优盘
- telnet无法访问
- java:eclipse:windows开发环境log4j系统找不到指定的路径
- 著名的软件项目开发和生命周期管理软件MKS.Code.Integrity.Enterprise.Edition.v12
- matlab 点云曲率,点云数据的主曲率和主方向估计方法
- 面试必备(背)-Linux八股文系列!
- 字模C语言入门,PCtoLCD2002完美版取字模工具软件及其步骤教程
- 软件项目经理应具备的素质和条件_软件项目经理的素质能力要求
- Swift中数组字典和plist文件的转换
- 相遇在这茫茫的网海里。你在天涯,我在海角
热门文章
- android attrs获取_Android 常用侧滑栏实现
- nginx重新加载php,如何使用nginx启动、停止和重新加载
- UCINET 社会网络分析工具
- 火箭轨道计算属于什么计算机技术,2018年计算机二级高级Office每日一练 2月27日...
- jenkins 手动执行_我常用的SpringBoot+Jenkins自动化部署技巧,贼好用,推荐给大家...
- mysql关联查询去重_MySQL外键和高级查询(连接查询、联合查询、子查询、去重查询)...
- php文件用什么浏览,什么是PHP文件 php文件用什么打开
- mysql 查数据 default无效_导入mysql数据的时候提示Field * doesn't have a default value解决方法...
- yaml数组解析_yaml格式详解
- 数据仓库--基本概念