effective c++:对象的赋值运算
operator 中处理”自我赋值“
operator=操作符缺省情况下返回引用——TYPE& TYPE::operator=(const TYPE&),原因很简单,operator=返回引用的理由是使你能在一个语句中连接多个赋值。
int x, y, z;
x = y = z = ; // chain of assignments
赋值采用右结合律,上面的代码被编译器解释为:
x = (y = (z = ));
在编译过程中,赋值是右结合的。说白了就是如果你想要玩一下多个赋值,operator=返回的东西必须是右(rhs)赋值。除了返回对对象自身的引用还能有什么呢?这就是为什么operator=最后一行总是返回对this的引用:
class Widget {
public:
...
Widget& operator=(const Widget& rhs) // return type is a reference to
{ // the current class
...
return *this; // return the left-hand object
}
...
};
再来看自我赋值,即对象被赋值给自己,假设建立一个class用来保存一个指针指向一块动态分配的bitmap
class Bitmap { ... };
class Widget {
...
private:
Bitmap *pb; // ptr to a heap-allocated object
};
下面是operator=代码,表面上看合理,但自我赋值时并不安全。
Widget&
Widget::operator=(const Widget& rhs) // unsafe impl. of operator=
{
delete pb; // stop using current bitmap
pb = new Bitmap(*rhs.pb); // start using a copy of rhs’s bitmap
return *this; // see Item 10
}
如果rhs与*this指向同一对象,第一句的delete pb就销毁了bitmap中调用的rhs.pb,这一问题的解决方案是copy and swap:
class Widget {
...
void swap(Widget& rhs); // exchange *this’s and rhs’s data;
... // see Item29 for details
};
Widget& Widget::operator=(const Widget& rhs)
{
Widget temp(rhs); // make a copy of rhs’s data
swap(temp); // swap *this’s data with the copy’s
return *this;
}
它先将rhs做一个复本,由这个复本与this交换数据来达到目的。
复制对象时确保复制对象内每个成员变量
类customer如下所示:
void logCall(const std::string& funcName); // make a log entry
class Customer {
public:
...
Customer(const Customer& rhs);
Customer& operator=(const Customer& rhs);
...
private:
std::string name;
};
Customer::Customer(const Customer& rhs)
: name(rhs.name) // copy rhs’s data
{
logCall("Customer copy constructor");
}
Customer& Customer::operator=(const Customer& rhs)
{
logCall("Customer copy assignment operator");
name = rhs.name; // copy rhs’s data
return *this; // see Item 10
}
这个程序完全正确,但当在类中加入一个成员变量,我们同时也要在复制运算中加入相应的变量复制。
class Date { ... }; // for dates in time
class Customer {
public:
... // as before
private:
std::string name;
Date lastTransaction;
};
如果忘记修改operator=函数,编译器不会提醒你,从而造成潜在的漏洞。
再来看派生类复制的情况
class PriorityCustomer: public Customer { // a derived class
public:
...
PriorityCustomer(const PriorityCustomer& rhs);
PriorityCustomer& operator=(const PriorityCustomer& rhs);
...
private:
int priority;
};
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
: priority(rhs.priority)
{
logCall("PriorityCustomer copy constructor");
}
PriorityCustomer&
PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
logCall("PriorityCustomer copy assignment operator");
priority = rhs.priority;
return *this;
}
PriorityCustomer好像是完全复制了成员变量,但每个PriorityCustomer类都还包含着基类的成员变量未被复制,PriorityCustomer类中的customer成分被不带实参的customer构造函数初始化,customer成员变量初始化为缺省的值。我们所要做的是提供一个第三方的函数来调用基类的复制函数。
注意两个错误用法:1、令copy assignment操作符调用copy构造函数是错误的,因为在这就像试图构造一个已存在的对象。2、令copy构造函数调用copy assignment操作符同样是错误的。构造函数用来出事后对象,而assignment操作符只实行与已初始化的对象身上。对一个尚未构造好的对象赋值,就像在一个尚未初始化的对象身上做“z只对已初始化对象才有意义”的事意义。
effective c++:对象的赋值运算的更多相关文章
- Effective C++ —— 构造/析构/赋值运算(二)
条款05 : 了解C++默默编写并调用哪些函数 编译器可以暗自为class创建default构造函数.copy构造函数.copy assignment操作符,以及析构函数. 1. default构造函 ...
- Effective C++ -- 构造析构赋值运算
05.了解C++默默编写并调用哪些函数 编译产生的析构函数时non-virtual,除非这个类的基类析构函数为virtual 成员变量中有引用和const成员时,无法自己主动生成copy assign ...
- 《Effective C++》第2章 构造/析构/赋值运算(2)-读书笔记
章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...
- 《Effective C++》第2章 构造/析构/赋值运算(1)-读书笔记
章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...
- Effective C++ 笔记二 构造/析构/赋值运算
条款05:了解C++默默编写并调用哪些函数 编译器默认声明一个default构造函数.一个copy构造函数.一个copy assignment操作符和一个析构函数.这些函数都是public且inlin ...
- Effective C++: 02构造、析构、赋值运算
05:了解C++默默编写并调用哪些函数 1:一个空类,如果你自己没声明,编译器就会为它声明(编译器版本的)一个copy构造函数.一个copy assignment操作符和一个析构函数.此外如果你没有声 ...
- C++中的构造函数,拷贝构造函数和赋值运算
关于C++中的构造函数,拷贝构造函数和赋值运算,以前看过一篇<高质量C++/C编程指南>的文章中介绍的很清楚,网上能搜索到,如果想详细了解这方面的知识可以参看一下这篇文章. 常见的给对象赋 ...
- js赋值运算的理解
简介 js引擎由于为了效率,很多时候的非直接量赋值都不是copy一份在赋值给新的变量,而是一个引用 ps:直接量:直接值数字字符串等 为什么使用len = doms.length; 里的len效率要比 ...
- Effective C++(11) 自我赋值(a=a)时会发生什么?
问题聚焦: 自我赋值看似有点愚蠢的行为,其实总会发生的 首先:它是合法的, 其次,它不一定是安全的, 再次,它有时候不是那么明显. 先看一个Demo class Widget { ... }; Wid ...
随机推荐
- USACO Section 3.2: Sweet Butter
这题我自己是用邻接矩阵+dijskstra方法来求的,第九个例子TLE.网上看了别人的代码,是用邻接表+BFS来完成. 这里可以学到两个小技巧,邻接表的表示方法和INT_MAX的表示方法. /* ID ...
- django-based blog- mezzanine
django-based blog- mezzanine zinnia 博客 hydra 暴力破解
- BZOJ 2173 整数的lqp拆分
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2173 题意:给出输出n.设一种拆分为n=x1+x2+x3,那么这种拆分的价值为F(x1) ...
- 《OD大数据实战》Hadoop伪分布式环境搭建
一.安装并配置Linux 8. 使用当前root用户创建文件夹,并给/opt/下的所有文件夹及文件赋予775权限,修改用户组为当前用户 mkdir -p /opt/modules mkdir -p / ...
- 不同浏览器JS获取浏览器高度和宽度
摘自:http://blog.csdn.net/lai_gb/archive/2009/07/04/4320956.aspx IE中: document.body.clientWidth ==> ...
- 【Todo】MQ学习-RabbitMQ, ActiveMQ, Kafka等
之前学习过RabbitMQ,并且还安装过.安装记录的文章如下: Erlang:http://www.cnblogs.com/charlesblc/p/5512380.html RabbitMQ:htt ...
- 基础组件_panel面板
面板作为承载其它内容的容器.这是构建其他组件的基础(比如:layout,tabs,accordion等).它还提供了折叠.关闭.最大化.最小化和自定义行为.面板可以很容易地嵌入到web页面的任何位置. ...
- 瞎折腾之 VS2013 Cordova项目的创建与配置
扯淡 什么是Cordova ? 网上查询的说明: Cordova是贡献给Apache后的开源项目,是从PhoneGap中抽出的核心代码,是驱动PhoneGap的核心引擎.你可以把他想象成类似于Webk ...
- MYSQL数据库管理之权限管理
经常遇到有网友在QQ群或者论坛上问关于mysql权限的问题,今天抽空总结一下关于这几年使用MYSQL的时候关于MYSQL数据库的权限管理的经验,也希望能对使用mysql的网友有所帮助! 一.MYSQL ...
- 深入理解 AngularJS 的 Scope(转)
一.遇到的问题 问题发生在使用 AngularJS 嵌套 Controller 的时候.因为每个 Controller 都有它对应的 Scope(相当于作用域.控制范围),所以 Controller ...