`

Effective c++学习笔记——条款11:在operateor=中自我赋值

 
阅读更多
Handle assignment to self in operator=
本条款的核心是关于c++对象的自我赋值,既然说是自我赋值,那么就会产生一些你意想不到的问题。首先看一下很有意思的“自我赋值”,简单例子
// self_opera.cpp : 定义控制台应用程序的入口点。
//2011/9/11-by wallwind-in revenco
#include "stdafx.h"
#include<iostream>
using namespace std;

class myClass { };

int _tmain(int argc, _TCHAR* argv[]) {
myClass my;
my = my;
system("pause");
return 0;
}

上段程序是可以通过的。可能有时候自我赋值是不能一眼就看出来的。比如以下程序语句:
a[i] = a[j]; //潜在的自我赋值
当i=j的时候,这便是个自我赋值
又如
*px = *py; //潜在的自我赋值
如果*px和*py恰好指向同一个东西,这也是自我赋值;
这些并不明显的自我赋值,是“别名”带来的结果:所谓“别名”就是“有一个以上的方法指称(指涉)某对象”。一般而言如果某段代码操作pointers或references而它们被用来“指向多个相同类型的对象”,就需要考虑这些对象是否为同一个。实际上两个对象只要来自同一个继承体系,它们甚至不需要声明为相同类型就可能造成“别名”,因为一个base class的reference或pointer可以指向一个derived class对象:
就如以下代码:
// self_opera.cpp : 定义控制台应用程序的入口点。
//2011/9/11-by wallwind-in revenco
#include "stdafx.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
class Base{ };
class Derived:public Base {};
void dosomething(const Base &rb, Derived& pb )
{
cout<<&rb<<endl;
cout<<&pb<<endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
const Base rb;
Derived pb;
dosomething(rb,pb);
return 0;
}
输出结果为:
其实自我赋值的情况是很容易出现问题的。
下面给大家举一个比较简单实用的,类似于书中的例子,myclass内部维护char指针类型,并指向一块内存空间,在进行operator操作时,首先释放当前myclass类型buffer所指向的空间,并将buffer指向赋值右边同一空间。如果是指向同一个myclass类型呢?buffer所指向空间已经被释放,调用ToString方法时访问了已释放的空间,其结果未有定义。
// self_opera.cpp : 定义控制台应用程序的入口点。
//2011/9/11-by wallwind-in revenco
#include "stdafx.h"
#include <stdlib.h>
#include <string.h>
class myclass{
public:
myclass() {
buffer = new char[255];
memset(buffer, 65, sizeof(char) * 255);
}
~myclass() {
delete[] buffer;
}
char* ToString() const { return buffer; }
myclass& operator=(const myclass& rhs) {
delete[] buffer;
buffer = rhs.buffer;
return *this;
}
private:
char *buffer;
};
int _tmain(int argc, _TCHAR* argv[]) {
myclass str1;
printf("%sn", str1.ToString());
str1 = str1;
printf("%sn", str1.ToString());
system("pause");
return 0;
}
欲阻止这种错误,传统做法是由operator=最前面的一个“证同测试”达到“自我赋值”的检验目的:
如下代码
myclass& operator=(const String& rhs) {
if (rhs == * this)////////////////////////////此处要重写“==”
return *this;
delete[] buffer;
buffer = rhs.buffer;
return *this;
}
这样做行得通。稍早我曾经提过,前一版operator=不仅不具备“自我赋值安全性”,也不具备“异常安全性”,这个新版本仍然存在异常方面的麻烦。比如书中的例子给出这样表述,如果, rhs.buffer;
是一块空地址,或者异常地址,依然会出现以上情况。那么就有了另一种技术保证异常的自我赋值了。
在operator=函数内手工排列语句(确保代码不但“异常安全”而且“自我赋值安全”)的一个替代方案是,使用所谓的copy and swap技术。这个技术和“异常安全性”有密切关系,所以由条款29详细说明。然而由于它是一个常见而够好的operator=撰写办法,所以值得看看其实现手法像什么样子:
// self_opera.cpp : 定义控制台应用程序的入口点。
//2011/9/11-by wallwind-in revenco
#include "stdafx.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
class myclass {
public:
myclass() {
_buffer = new char[255];
memset(_buffer, 65, sizeof(char) * 255);
}
myclass(const myclass& rhs) {
_buffer = new char[255];
memcpy(_buffer, rhs._buffer, sizeof(char) * 255);
}
myclass& operator=(const myclass& rhs) {
myclass temp(rhs);
swap(temp);
return *this;
}
char* ToString() const { return _buffer; }
private:
void swap(const myclass& rhs) {
delete[] _buffer;
_buffer = rhs._buffer;
}
char *_buffer;
};
int _tmain(int argc, _TCHAR* argv[]) {
myclass str1;
printf("%sn", str1.ToString());
str1 = str1;
printf("%sn", str1.ToString());
system("pause");
return 0;
}
我个人比较忧虑这个做法,我认为它为了伶俐巧妙的修补而牺牲了清晰性。然而将“copy 动作”从函数本体内移至“函数参数构造阶段”却可令编译器有时生成更高效的代码。

请记住:

1、确保当对象自我赋值时operator=有良好行为。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap。

2、确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。

分享到:
评论

相关推荐

    端午送祝福语小程序源码(可对接流量主)

    该小程序的作用就是祝福语生成距离端午节也不远了,可以抓住机会蹭一波流量用户可以点击直接发送祝福语给好友 分享的时候会显示用。

    基于Springboot微服务的车联网位置信息管理软件的设计与实现+论文

    基于Spring Boot微服务的车联网位置信息管理软件旨在通过现代化技术提升车辆位置信息的实时监控与管理效率。以下是该系统的功能模块和技术实现的简要介绍: 系统功能模块 车辆定位与追踪:通过集成GPS等定位技术,实时获取车辆位置信息,并提供车辆追踪功能。 位置信息管理:存储、查询、更新车辆位置信息,支持历史轨迹回放和位置数据统计分析。 报警与预警:根据预设规则,对异常位置信息进行报警和预警,如超速、越界等。 用户管理:支持用户注册、登录、权限管理等操作,确保系统安全和数据保密。 技术实现 后端技术:采用Spring Boot框架构建微服务架构,利用Maven进行项目管理,确保系统的高性能和稳定性。 数据库:使用MySQL数据库存储车辆位置信息、用户数据等关键信息,支持高效的数据查询和统计分析。 定位技术:集成GPS等定位技术,实现车辆位置的实时获取和追踪。 前端技术:结合Vue.js等前端框架,构建直观、友好的用户界面,提供丰富的交互体验。 该系统通过Spring Boot微服务架构和现代化技术,实现了车联网位置信息的实时监控与管理,为车辆管理提供了有力的技术支持。

    毕业设计MATLAB_SIFT特征提取.zip

    毕业设计MATLAB_SIFT特征提取.zip

    微信小程序-城市天气2小程序项目源码-原生开发框架-含效果截图示例.zip

    微信小程序凭借其独特的优势,在移动应用市场中占据了一席之地。首先,微信小程序无需下载安装,用户通过微信即可直接使用,极大地降低了使用门槛。其次,小程序拥有与原生应用相近的用户体验,同时加载速度快,响应迅速,保证了良好的使用感受。此外,微信小程序还提供了丰富的API接口,支持开发者轻松接入微信支付、用户授权等功能,为开发者提供了更多的可能性。 微信小程序-项目源码-原生开发框架。想要快速打造爆款小程序吗?这里有一份原生开发框架的项目源码等你来探索!基于微信小程序的强大生态,这份源码将带你领略原生开发的魅力,实现快速迭代与高效开发。从用户授权到微信支付,从界面设计到功能实现,一切尽在掌握。赶快下载查看,让你的小程序项目在竞争激烈的市场中脱颖而出!

    医师定期考核工作安排表.docx

    医师定期考核工作安排表.docx

    yolo学习导航.txt

    yolov10

    Golang_Go100个错误和如何避免它们.zip

    Golang_Go100个错误和如何避免它们

    京麒CTF2024-Re-easy-wasm(wasm逆向分析)

    京麒CTF2024-Re-easy-wasm(wasm逆向分析)

    基于Springboot+Vue的米家商城的设计与实现+论文

    基于Spring Boot和Vue的米家商城设计与实现,系统致力于提供用户一个便捷、多样化的购物体验。以下是系统功能模块和技术实现的简要介绍: 系统功能模块 用户模块: 注册登录:支持用户快速注册和登录。 个人中心:展示用户信息、订单记录、地址管理等。 购物车:管理用户选中的商品,支持结算和修改。 商品模块: 商品展示:按分类或搜索展示商品详情。 商品详情:展示商品详细信息,包括价格、评价等。 购物车加入:用户可将商品加入购物车。 订单模块: 订单生成:用户提交订单,系统生成订单信息。 订单查询:用户可查询自己的订单状态。 订单支付:支持多种支付方式,确保交易安全。 管理员模块: 商品管理:添加、编辑、删除商品信息。 用户管理:查看、编辑用户信息,管理用户权限。 订单管理:查看、处理用户订单。 技术实现 后端:采用Spring Boot框架,基于Java语言开发,提供RESTful API接口,确保系统的高性能和稳定性。 前端:使用Vue.js框架构建用户界面,通过Axios与后端进行通信,实现数据交互和展示。 数据库:采用MySQL数据库存储商品、用户、订单等关键数据。 开发工具:

    Golang_Gogithuubs在线模式迁移工具MySQL.zip

    Golang_Gogithuubs在线模式迁移工具MySQL

    类型转换之显式转换习题及参考答案

    类型转换之显式转换习题及参考答案

    libaa-devel-1.4.0-0.rc5.34.mga8.armv7hl.rpm

    安装:rpm -i xx.rpm

    音乐播放器带后端.zip

    小程序开发案例

    微信小程序-Railay:整体框架小程序项目源码-原生开发框架-含效果截图示例.zip

    微信小程序凭借其独特的优势,在移动应用市场中占据了一席之地。首先,微信小程序无需下载安装,用户通过微信即可直接使用,极大地降低了使用门槛。其次,小程序拥有与原生应用相近的用户体验,同时加载速度快,响应迅速,保证了良好的使用感受。此外,微信小程序还提供了丰富的API接口,支持开发者轻松接入微信支付、用户授权等功能,为开发者提供了更多的可能性。 微信小程序-项目源码-原生开发框架。想要快速打造爆款小程序吗?这里有一份原生开发框架的项目源码等你来探索!基于微信小程序的强大生态,这份源码将带你领略原生开发的魅力,实现快速迭代与高效开发。从用户授权到微信支付,从界面设计到功能实现,一切尽在掌握。赶快下载查看,让你的小程序项目在竞争激烈的市场中脱颖而出!

    C语言课程设计(成绩管理系统)源程序

    C语言课程设计(成绩管理系统)源程序

    剪辑必备AE红色粒子Banner背景-480P 清晰-AVC.mp4

    这是一个为视频编辑和动画制作者设计的动态背景素材。 它采用了先进的Adobe After Effects(简称AE)技术,创造出一个充满活力和视觉冲击力的红色粒子效果。 适用于制作各种视频内容的背景,如广告、宣传片、社交媒体视频等。 视频以480P的清晰度呈现,确保了即使在较低分辨率的播放设备上也能保持画面的清晰度和细节。采用AVC(Advanced Video Coding)编码格式,这是一种高效的视频压缩技术,能够在保持画质的同时,减少文件的大小,便于存储和传输。 红色粒子的动态效果,如同烟花绽放,又似星河流动,充满了动感和现代感。粒子在屏幕上自由地飘散、聚集,形成各种美丽的图案和形状,为视频增添了无限的想象空间和创意表现力。这种粒子效果可以很好地吸引观众的注意力,同时也为视频内容提供了一个完美的视觉框架。 无论是用于商业宣传,还是个人视频创作,这个红色粒子Banner背景都能够提升视频的专业感和吸引力。它易于编辑和定制,用户可以根据自己的需求调整粒子的颜色、速度、密度等参数,创造出独一无二的视觉效果。总之,这是一个多功能、高效率的视频背景资源,值得每一位视频制作者拥有。

    Dev-cpp软件压缩包

    Dev-cpp软件压缩包供大家下载!

    Golang_Gogitlfs自定义传输适配器,它简单地使用一个文件夹作为远程LFS媒体存储,例如共享NAS文件夹.zip

    Golang_Gogitlfs自定义传输适配器,它简单地使用一个文件夹作为远程LFS媒体存储,例如共享NAS文件夹

    2023 高级软件测试开发工程师全套视频.zip

    资源目录:2023 高级软件测试开发工程师,本课程共77.26G ├──测试开发 | ├──21–前端技术之JQuery NO.69 | | ├──课件资料 | | ├──章节1 JavaScript基础入门 | | ├──章节2 流程控制语句 | | ├──章节3 Function 函数 | | ├──章节4 正则表达式 | | ├──章节5 DOM操作 | | ├──章节6 jQuery应用实践 | | └──章节7 jQuery源码分析 | ├──Flask框架NO.145 | | ├──1,虚拟化环境 | | ├──2,视图和URL | | ├──3,Jinjia2模板 | | ├──4,Flask高级1 | | ├──5,Flask数据库和ORM框架 | | └──6,Flask-restful | ├──MongoDB基础入门到企业级应用(官网未更新) | ├──MySQL与Python的交互-981 | | └──章节1-MySQL与Python的交互 | ├──PyQt桌面工具开发(官网未更新) | ├──Redis_高效的NoSQL数据库-32 | | ├──章节1-

    notebook-6.5.0a0.tar.gz

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

Global site tag (gtag.js) - Google Analytics