⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 [12] assignment operators, c++ faq lite.htm

📁 c++faq。里面有很多关于c++的问题的解答。
💻 HTM
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
<!-- saved from url=(0058)http://www.sunistudio.com/cppfaq/assignment-operators.html -->
<HTML><HEAD><TITLE>[12] Assignment operators, C++ FAQ Lite</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META http-equiv=Content-Language content=zh-cn>
<META content=assignment-operators.html name=FILENAME>
<META content="[12] Assignment operators, C++ FAQ Lite" name=ABSTRACT>
<META content=cline@parashift.com name=OWNER>
<META content="Marshall Cline, cline@parashift.com" name=AUTHOR>
<META content="MSHTML 6.00.2462.0" name=GENERATOR>
<META content=FrontPage.Editor.Document name=ProgId><LINK rev=made 
href="mailto:cline@parashift.com"><LINK 
href="[12] Assignment operators, C++ FAQ Lite.files/cpp-faq.css" type=text/css 
rel=stylesheet></HEAD>
<BODY>
<H1><A name=top></A>[12] 赋值算符<BR><SMALL><SMALL>(Part of <A 
href="http://www.sunistudio.com/cppfaq/index.html"><EM>C++ FAQ Lite</EM></A>, <A 
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.2]">Copyright&nbsp;&copy; 
1991-2001</A>, <A href="http://www.parashift.com/" target=OutsideTheFAQ>Marshall 
Cline</A>, <A 
href="mailto:cline@parashift.com">cline@parashift.com</A>)</SMALL></SMALL></H1>
<P>简体中文版翻译:<A href="http://www.sunistudio.com/nicrosoft">申旻</A>,<A 
href="mailto:nicrosoft@sunistudio.com">nicrosoft@sunistudio.com</A>(<A 
href="http://www.sunistudio.com/">东日制作室</A>,<A 
href="http://www.sunistudio.com/asp/sunidoc.asp">东日文档</A>)</P>
<HR>

<H3>FAQs in section [12]:</H3>
<UL>
  <LI><A 
  href="http://www.sunistudio.com/cppfaq/assignment-operators.html#[12.1]">[12.1] 
  什么是“自赋值”?</A> 
  <LI><A 
  href="http://www.sunistudio.com/cppfaq/assignment-operators.html#[12.2]">[12.2] 
  为什么应该当心“自赋值”?</A> 
  <LI><A 
  href="http://www.sunistudio.com/cppfaq/assignment-operators.html#[12.3]">[12.3] 
  好,好;我会处理自赋值的。但如何做呢?</A> <IMG alt=UPDATED! 
  src="[12] Assignment operators, C++ FAQ Lite.files/updated.gif"> </LI></UL>
<P>
<HR>

<P><A name=[12.1]></A>
<DIV class=FaqTitle>
<H3>[12.1] 什么是“自赋值”?</H3></DIV>
<P>自赋值就是将对象赋值给本身。例如, 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;#include&nbsp;"Fred.hpp"&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;声明 
<TT>Fred</TT> 
类&nbsp;</EM><TT><BR>&nbsp;<BR>&nbsp;void&nbsp;userCode(Fred&amp;&nbsp;x)<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;x;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;自赋值</EM><TT><BR>&nbsp;} 
</TT></DIV>
<P>很明显,以上代码进行了显式的自赋值。但既然多个指针或引用可以指向相同对象(别名),那么进行了自赋值而不知道的情况也是可能的: 
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;#include&nbsp;"Fred.hpp"&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;</EM><EM>声明 
</EM><EM><TT>Fred</TT> 
类</EM><TT><BR>&nbsp;<BR>&nbsp;void&nbsp;userCode(Fred&amp;&nbsp;x,&nbsp;Fred&amp;&nbsp;y)<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;y;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;如果<TT>&amp;x&nbsp;==&nbsp;&amp;y</TT>就可能是自赋值</EM><TT><BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;int&nbsp;main()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;Fred&nbsp;z;<BR>&nbsp;&nbsp;&nbsp;userCode(z,&nbsp;z);<BR>&nbsp;} 
</TT></DIV>
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#top">Top</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[12.2]></A>
<DIV class=FaqTitle>
<H3>[12.2] 为什么应该当心“自赋值”?</H3></DIV>
<P>如果不注意<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#[12.1]">自赋值</A>,将会使你的用户遭受非常微妙的并且一般来说非常严重的bug。例如,如下的类在自赋值的情况下将导致灾难: 

<P>
<DIV 
class=CodeBlock><TT>&nbsp;class&nbsp;Wilma&nbsp;{&nbsp;};<BR>&nbsp;<BR>&nbsp;class&nbsp;Fred&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;Fred()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;p_(new&nbsp;Wilma())&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;}<BR>&nbsp;&nbsp;&nbsp;Fred(const&nbsp;Fred&amp;&nbsp;f)&nbsp;&nbsp;&nbsp;:&nbsp;p_(new&nbsp;Wilma(*f.p_))&nbsp;{&nbsp;}<BR>&nbsp;&nbsp;~Fred()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;delete&nbsp;p_;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;Fred&amp;&nbsp;operator=&nbsp;(const&nbsp;Fred&amp;&nbsp;f)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;差劲的代码:没有处理自赋值!</EM><TT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;p_;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;Line&nbsp;#1</EM><TT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p_&nbsp;=&nbsp;new&nbsp;Wilma(*f.p_);&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;Line&nbsp;#2</EM><TT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;*this;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;Wilma*&nbsp;p_;<BR>&nbsp;}; 
</TT></DIV>
<P>如果有人将 <TT>Fred </TT>对象赋给其本身,由于<TT>*this</TT>和 <TT>f</TT> 是同一个对象,line 
#1同时删除了<TT>this-&gt;p_</TT>和<TT>f.p_</TT>。而 line 
#2使用了已经不存在的对象<TT>*f.p_</TT>,这样很可能导致严重的灾难。
<P>作为 <TT>Fred</TT><TT> </TT>类的作者,你最起码有责任<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#[12.3]">确信在<TT>Fred</TT>对象上自赋值是无害的</A>。不要假设用户不会在对象上这样做。如果对象由于自赋值而崩溃,那是<I>你的</I>过失。
<BLOCKQUOTE>
  <P><SMALL>另外:上述的</SMALL><SMALL><TT>Fred::operator=&nbsp;(const&nbsp;Fred&amp;)</TT></SMALL><SMALL>还有第二个问题:如果在执行</SMALL><SMALL><TT>new&nbsp;Wilma(*f.p_)</TT></SMALL><SMALL>时,<A 
  href="http://www.sunistudio.com/cppfaq/exceptions.html">抛出了异常</A>(例如,<A 
  href="http://www.sunistudio.com/cppfaq/freestore-mgmt.html#[16.5]">内存不够的异常</A>或者</SMALL><A 
  href="http://www.sunistudio.com/cppfaq/exceptions.html#[17.2]"><TT><SMALL>Wilma</SMALL></TT><SMALL>的拷贝构造函数中的异常</SMALL><SMALL><!--rawtext:[17.2]:rawtext--></SMALL></A><SMALL>),</SMALL><SMALL> 
  <TT>this-&gt;p_</TT></SMALL><SMALL>将成为悬空指针——它所指向的内存不再是可用的。这可以通过在删除就对象前创建对象来解决。</SMALL></P></BLOCKQUOTE>
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#top">Top</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[12.3]></A>
<DIV class=FaqTitle>
<H3>[12.3] 好,好;我会处理自赋值的。但如何做呢? <IMG alt=UPDATED! 
src="[12] Assignment operators, C++ FAQ Lite.files/updated.gif"></H3></DIV><SMALL><EM>[Recently 
reworded the last paragraph (on 7/00). <A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#[13.3]">Click 
here to go to the next FAQ in the "chain" of recent changes<!--rawtext:[13.3]:rawtext--></A>.]</EM></SMALL> 
<P><A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#[12.2]">在你创建类的每时每刻,都应该当心自赋值</A>。这并不意味着需要为你所有的类都增加额外的代码:只要对象优美地处理自赋值,而不管是否必须增加额外的代码。 

<P>如果不需要为赋值算符增加额外代码,这里有一个简单而有效的技巧: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;Fred&amp;&nbsp;Fred::operator=&nbsp;(const&nbsp;Fred&amp;&nbsp;f)<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(this&nbsp;==&nbsp;&amp;f)&nbsp;return&nbsp;*this;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;优美地处理<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#[12.1]">自赋值</A></EM><TT><BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;此处写正常赋值的代码...</EM><TT><BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;return&nbsp;*this;<BR>&nbsp;} 
</TT></DIV>
<P>显式的测试并不总是必要的。例如,如果修正<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#[12.2]">前一个 FAQ<!--rawtext:[12.2]:rawtext-->中的赋值算符</A>使之<A 
href="http://www.sunistudio.com/cppfaq/freestore-mgmt.html#[16.5]">处理<TT>new</TT><!--rawtext:[16.5]:rawtext-->抛出的异常</A>和/或<TT>Wilma</TT>类的<A 
href="http://www.sunistudio.com/cppfaq/exceptions.html#[17.2]">拷贝构造函数抛出的异常</A>,可能会写出如下的代码。注意这段代码有(令人高兴的)自动处理自赋值的附带效果:
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;Fred&amp;&nbsp;Fred::operator=&nbsp;(const&nbsp;Fred&amp;&nbsp;f)<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;这段代码优美地(但隐含的)处理<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#[12.1]">自赋值</A></EM><TT><BR>&nbsp;&nbsp;&nbsp;Wilma*&nbsp;tmp&nbsp;=&nbsp;new&nbsp;Wilma(*f.p_);&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;如果<A 
href="http://www.sunistudio.com/cppfaq/exceptions.html">异常</A>在此处被抛出也没有问题</EM><TT><BR>&nbsp;&nbsp;&nbsp;delete&nbsp;p_;<BR>&nbsp;&nbsp;&nbsp;p_&nbsp;=&nbsp;tmp;<BR>&nbsp;&nbsp;&nbsp;return&nbsp;*this;<BR>&nbsp;} 
</TT></DIV>
<P>在象这个例子的情况下(自赋值是无害的但是低效),一些程序员想通过增加另外的不必要的测试,如“<TT>if&nbsp;(this&nbsp;==&nbsp;&amp;f)&nbsp;return&nbsp;*this;</TT>”来改善自赋值时的效率。通常来说,使自赋值情况更高效而使得非自赋值情况更低效的折衷是错误的。例如,为<TT>Fred</TT>类的赋值算符增加如上的<TT>if</TT>测试会使得非自赋值情况更低效(一个额外的(而且不必要的)条件分支)。如果自赋值实际上一千次才发生一次,那么 
<TT>if</TT><TT> </TT>将浪费99.9%的时间周期。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#top">Top</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=bottom></A><A href="mailto:cline@parashift.com"><IMG height=26 
alt=E-Mail src="[12] Assignment operators, C++ FAQ Lite.files/mbox.gif" 
width=89>&nbsp;E-mail the author</A><BR>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/index.html"><EM>C++ FAQ Lite</EM></A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/index.html#table-of-contents">Table&nbsp;of&nbsp;contents</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/subject-index.html">Subject&nbsp;index</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.1]">About&nbsp;the&nbsp;author</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.2]">&copy;</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/on-line-availability.html#[2.2]">Download&nbsp;your&nbsp;own&nbsp;copy</A>&nbsp;]<BR><SMALL>Revised 
Apr 8, 2001</SMALL> </P></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -