拷贝赋值和move赋值对于自身赋值的判断

oniisama 2016-03-02 09:52:50
看c++primer上move赋值的代码有这么一行
StrVec &StrVec::operator=(StrVec &&rhs) noexcept
{
// direct test for self-assignment
if (this != &rhs) {
//...
}
return *this;
}

判断对方地址是否和this指针一样。而拷贝赋值却没有作这么一个判断,这是为什么呢?
...全文
439 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2016-04-18
  • 打赏
  • 举报
回复
很多时候,使用的工具越先进,人越笨;得到得越轻松,人越懒。 请牢记:源代码本身的书写是否结构化或面向对象或符合设计模式或敏捷…并不重要,重要的是你是否使用结构化或面向对象或符合设计模式或敏捷…的方法命名标识符、阅读、修改、检查、测试源代码。 意思是你程序结构看上去再合理,再简洁,也不一定比看上去一团乱麻的程序结构在运行或修改时更不易出错,更方便修改,出错了更容易找到哪里出错和具体出错的原因,更容易改正错误。 试对比 图书馆(对图书的分类够结构化了吧) 和 搜索引擎(可看作是扁平化任何结构数据,仅支持全文检索) 哪个处理信息更方便、更高效。 所以 与其费劲去重构代码让其看上去更简洁、更合理 不如费劲学习grep、sed、awk、……这类全文搜索和批处理编辑的工具。 结构越复杂,越难修改,越难除错。 有时(甚至大多数时候),看上去越合理、越简洁的代码,运行起来性能越差,出错时查找原因越难,找到出错原因后改正越费劲。 程序员要做的不是尽力避免错误,而是聚焦在快速发现并改正错误。真正以快速方式轻易解决错误,“快速的失败”远胜过“预防错误”。Fred George 前微软C#编辑器的开发主管Jay Bazuzi列出的一些有助于找到正确方向的问题;他觉得前同事们应该用这些问题来问自己;实际上不管在哪里工作的开发者们都应该经常问问自己这些问题: ◆“要保证这个问题不会再出现,我该怎么做?” ◆“要想少出些Bug,我该怎么做?” ◆“要保证Bug容易被修复,我该怎么做?” ◆“要保持对变化的快速响应,我该怎么做?” ◆“要保证我的软件的运行速度,我该怎么做?” 如果大多数团队都能不时问一下自己,必定会从中得益,因为这些都是真正强而有力的问题。
ri_aje 2016-04-17
  • 打赏
  • 举报
回复
引用 11 楼 sdghchj 的回复:
对楼上回答的无语,人家说的拷贝赋值,又没说拷贝构造。 不管是拷贝赋值,还是move赋值,都可以先判断地址是否不一样后再处理,效率上会高点。 但不判断,也是可以的,自己赋值给自己时效率低点而已。
你这么说就显得经验不足了,这不仅仅是效率低点的问题,而是关乎程序正确性的问题,因为凡是需要自己动手写复制赋值的类,基本都管理着类似指针这样的特殊资源。这种情况下,大多数人(包括我自己)写复制赋值函数的时候,脑子里自然假设了目标对象和源对象是不同的(虽然他们都未必意识到了这些头脑预设的存在)写出的程序也是处理这种赋值的时候好用,对于自身赋值等 特殊情况,就直接挂了,比如这样的字符串复制:

op = (string const& source)
{
 delete [] this.ptr;
 this.ptr = new char [source.size];
 copy(source.begin,source.end,this.ptr);
}
诚然,不需要检测对象是否相同也能正确工作的实现存在,但首先程序员得知道自己的算法可能有问题,然后他还得专门动东脑子琢磨一下怎么对付自赋值。靠正规教育教导程序员每时每刻防止自己犯类似错误显然是不现实的,最简单可行且能够大规模传播的方法就是直接避免自赋值。
lm_whales 2016-04-16
  • 打赏
  • 举报
回复
引用 12 楼 zhao4zhong1 的回复:
对于某些硬件特性比较特殊的存储介质,即使自己赋值给自己,也不能跳过。
那种情况单独处理就可以了 这种避免自我复制的做法,只是针对指针的(以及某些类似指针的句柄的) 这些指针或者句柄,一次只能拥有一个资源。 如果不避开,重新分配资源,就会造成资源泄漏 这和那不冲突。
赵4老师 2016-04-15
  • 打赏
  • 举报
回复
对于某些硬件特性比较特殊的存储介质,即使自己赋值给自己,也不能跳过。
sdghchj 2016-04-15
  • 打赏
  • 举报
回复
对楼上回答的无语,人家说的拷贝赋值,又没说拷贝构造。 不管是拷贝赋值,还是move赋值,都可以先判断地址是否不一样后再处理,效率上会高点。 但不判断,也是可以的,自己赋值给自己时效率低点而已。
ri_aje 2016-04-15
  • 打赏
  • 举报
回复
引用 9 楼 u012453583 的回复:
楼上基本说的都没在点上 开始我也是纠结这个问题 后来想通 从书上看出,拷贝控制重点在于拷贝,所以对于拷贝赋值来说就算是自身赋值也要本身新建内存来存放原来的数据并释放掉原内存(过程就是利用另外变量中转),这样就完成拷贝的目的,这个过程变量名没发生变化仅仅是内存改变。当然,也是可以按你所说的加入地址判断。所以这个地方尤物皆可。 移动赋值来说重点是移动,节约资源和时间,书中为了显示移动的优点就自然的添加了(或者说自然在拷贝赋值中移除了)地址判断。 无论拷贝赋值和移动赋值,对于自赋值来说,这是两者的共通之处。 以上就是我个人的理解。
这不是想通了,这是想歪了。
追风3714 2016-04-14
  • 打赏
  • 举报
回复
楼上基本说的都没在点上 开始我也是纠结这个问题 后来想通 从书上看出,拷贝控制重点在于拷贝,所以对于拷贝赋值来说就算是自身赋值也要本身新建内存来存放原来的数据并释放掉原内存(过程就是利用另外变量中转),这样就完成拷贝的目的,这个过程变量名没发生变化仅仅是内存改变。当然,也是可以按你所说的加入地址判断。所以这个地方尤物皆可。 移动赋值来说重点是移动,节约资源和时间,书中为了显示移动的优点就自然的添加了(或者说自然在拷贝赋值中移除了)地址判断。 无论拷贝赋值和移动赋值,对于自赋值来说,这是两者的共通之处。 以上就是我个人的理解。
lm_whales 2016-03-03
  • 打赏
  • 举报
回复
至于有人 故意让一个对象构造两次,这种错误,C++一般都不说。 等到代码出问题,让他自己去领悟
lm_whales 2016-03-03
  • 打赏
  • 举报
回复
1) opertor =: operator = 很有可能遇到 a=a 的情况 因为 C++引用和 指针 都会产生别名,此时很难追溯以确定是否同一个对象 因此,你在写程序的时候,很难避免 赋值号 两边其实是同一个对象的情况。 编译器也同样,难以检查出来,赋值号 两边其实是同一个对象的情况。 所以 operator = 一般需要判断 两个对象,是否同一对象。 2) 拷贝构造函数 而 拷贝构造函数,构造的是个新对象 参数是个旧对象,这在C++语法上,就可以保证是两个不同的对象 因为一个对象,不会重复构造两次。
pengzhixi 2016-03-03
  • 打赏
  • 举报
回复
额 一个赋值,一个拷贝构造,两种不同的语义,拷贝构造重点在构造一个新对象,赋值(operator=)重点在于修改已有的对象。
fefe82 2016-03-03
  • 打赏
  • 举报
回复
引用 4 楼 pengzhixi 的回复:
拷贝赋值不需要啊,拷贝赋值本来就是构造一个新对象啊,肯定和原来的久对象不是同一个了。
class A a; a = a; 还是可以的。
pengzhixi 2016-03-03
  • 打赏
  • 举报
回复
拷贝赋值不需要啊,拷贝赋值本来就是构造一个新对象啊,肯定和原来的久对象不是同一个了。
ri_aje 2016-03-03
  • 打赏
  • 举报
回复
应该有才好。
relaxisland 2016-03-02
  • 打赏
  • 举报
回复
要的, 比如,如果你的成员有一个指针,需要拷贝分配内存,并从拷贝元拷贝 如果不区分拷贝元是不是本身。 直接分配新内存,并赋值给那个成员变量。 就把原来的指针给冲掉了。
fefe82 2016-03-02
  • 打赏
  • 举报
回复
也应该有。 不过根据函数内容,有时没有也不会出错。

64,685

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧