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

📄 ec5.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<UL><PRE>
delete &amp;four;                          // retrieve pointer
                                       // and delete it
</PRE>
</UL><A NAME="6689"></A>
<P><A NAME="dingp68"></A>
The odds are vanishingly small. Remember, if only a <I>single caller</I> of <CODE>operator*</CODE> fails to follow the rules, you have a memory <NOBR>leak.<SCRIPT>create_link(68);</SCRIPT>
</NOBR></P>
<A NAME="6690"></A>
<P><A NAME="dingp69"></A>
<A NAME="p134"></A>Returning dereferenced pointers has a second, more serious, problem, because it persists even in the presence of the most conscientious of programmers. Often, the result of <CODE>operator*</CODE> is a temporary intermediate value, an object that exists only for the purposes of evaluating a larger expression. For <NOBR>example:<SCRIPT>create_link(69);</SCRIPT>
</NOBR></P>
<A NAME="6692"></A>
<UL><PRE>Rational one(1), two(2), three(3), four(4);
Rational product;
</PRE>
</UL><A NAME="6693"></A>
<UL><PRE>product = one * two * three * four;
</PRE>
</UL><A NAME="6694"></A>
<P><A NAME="dingp70"></A>
Evaluation of the expression to be assigned to <CODE>product</CODE> requires three separate calls to <CODE>operator*</CODE>, a fact that becomes more evident when you rewrite the expression in its equivalent functional <NOBR>form:<SCRIPT>create_link(70);</SCRIPT>
</NOBR></P>
<A NAME="6695"></A>
<UL><PRE>product = operator*(operator*(operator*(one, two), three), four);
</PRE>
</UL><A NAME="6696"></A>
<P><A NAME="dingp71"></A>
You know that each of the calls to <CODE>operator*</CODE> returns an object that needs to be deleted, but there is no possibility of applying <CODE>delete</CODE>, because none of the returned objects has been saved <NOBR>anywhere.<SCRIPT>create_link(71);</SCRIPT>
</NOBR></P>
<A NAME="6697"></A>
<P><A NAME="dingp72"></A>
The only solution to this difficulty is to ask clients to code like <NOBR>this:<SCRIPT>create_link(72);</SCRIPT>
</NOBR></P>
<A NAME="6698"></A>
<UL><PRE>const Rational&amp; temp1 = one * two;
const Rational&amp; temp2 = temp1 * three;
const Rational&amp; temp3 = temp2 * four;
</PRE>
</UL><A NAME="6699"></A>
<UL><PRE>delete &amp;temp1;
delete &amp;temp2;
delete &amp;temp3;
</PRE>
</UL><A NAME="6700"></A>
<P><A NAME="dingp73"></A>
Do that, and the best you can hope for is that people will ignore you. More realistically, you'd be skinned alive, or possibly sentenced to ten years hard labor writing microcode for waffle irons and toaster <NOBR>ovens.<SCRIPT>create_link(73);</SCRIPT>
</NOBR></P>
<A NAME="6701"></A>
<P><A NAME="dingp74"></A>
Learn your lesson now, then: writing a function that returns a dereferenced pointer is a memory leak just waiting to <NOBR>happen.<SCRIPT>create_link(74);</SCRIPT>
</NOBR></P>
<A NAME="25935"></A>
<P><A NAME="dingp75"></A>
By the way, if you think you've come up with a way to avoid the undefined behavior inherent in returning a reference to a local object and the memory leak haunting the return of a reference to a heap-allocated object, turn to <A HREF="./EC4_FR.HTM#6210" TARGET="_top">Item 23</A> and read why returning a reference to a local <CODE>static</CODE> object also fails to work correctly. It may save you the trouble of seeking medical care for the arm you're likely to strain trying to pat yourself on the <NOBR>back.<SCRIPT>create_link(75);</SCRIPT>
</NOBR></P>
<!-- SectionName="E32: Postpone variable defs as long as possible" -->
<A NAME="25939"></A><A NAME="p135"></A><A NAME="26547"></A>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="#6650">Item 31: Never return a reference to a local object or to a dereferenced pointer initialized by new within the function.</A>
                            <BR>Continue to <A HREF="#6729">Item 33: Use inlining judiciously.</A></FONT></DIV>


<P><A NAME="dingp76"></A><FONT ID="eititle">Item 32: &nbsp;Postpone variable definitions as long as possible.</FONT><SCRIPT>create_link(76);</SCRIPT>
</P>

<P><A NAME="dingp77"></A>
So you subscribe to the C philosophy that variables should be defined at the beginning of a block. Cancel that subscription! In C++, it's unnecessary, unnatural, and <NOBR>expensive.<SCRIPT>create_link(77);</SCRIPT>
</NOBR></P>
<A NAME="26549"></A>
<P><A NAME="dingp78"></A>
Remember that when you define a variable of a type with a constructor or destructor, you incur the cost of construction when control reaches the variable's definition, and you incur the cost of destruction when the variable goes out of scope. This means there's a cost associated with unused variables, so you want to avoid them whenever you <NOBR>can.<SCRIPT>create_link(78);</SCRIPT>
</NOBR></P>
<A NAME="26564"></A>
<P><A NAME="dingp79"></A>
Suave and sophisticated in the ways of programming as I know you to be, you're probably thinking you never define unused variables, so this Item's advice is inapplicable to your tight, lean coding style. You may need to think again. Consider the following function, which returns an encrypted version of a password, provided the password is long enough. If the password is too short, the function throws an exception of type <CODE>logic_error</CODE>, which is defined in the standard C++ library (see <A HREF="./EC7_FR.HTM#8392" TARGET="_top">Item 49</A>):<SCRIPT>create_link(79);</SCRIPT>
</P>
<A NAME="26565"></A>
<UL><PRE>// this function defines the variable "encrypted" too soon
string encryptPassword(const string&amp; password)
{
  string encrypted;
</PRE>
</UL><A NAME="26566"></A>
<UL><PRE>  if (password.length() &lt; MINIMUM_PASSWORD_LENGTH) {
     throw logic_error("Password is too short");
  }
</PRE>
</UL><A NAME="26567"></A>
<UL><PRE>  <i>do whatever is necessary to place an encrypted
  version of</i> password <i>in</i> encrypted;
</PRE>
</UL><A NAME="26568"></A>
<UL><PRE>  return encrypted;
}
</PRE>
</UL><A NAME="26548"></A>
<P><A NAME="dingp80"></A>
The object <CODE>encrypted</CODE> isn't <I>completely</I> unused in this function, but it's unused if an exception is thrown. That is, you'll pay for the construction and destruction of <CODE>encrypted</CODE> even if <CODE>encryptPassword</CODE> throws an exception (see also <A HREF="../MEC/MC3_FR.HTM#40989" TARGET="_top">Item M15</A>). As a result, you're better off postponing <CODE>encrypted</CODE>'s definition until you <I>know</I> you'll need <NOBR>it:<SCRIPT>create_link(80);</SCRIPT>
</NOBR></P>
<A NAME="26612"></A>
<UL><PRE><A NAME="p136"></A>// this function postpones "encrypted"'s definition until
// it's truly necessary
string encryptPassword(const string&amp; password)
{
  if (password.length() &lt; MINIMUM_PASSWORD_LENGTH) {
    throw logic_error("Password is too short");
  }
</PRE>
</UL><A NAME="26619"></A>
<UL><PRE>  string encrypted;
</PRE>
</UL><A NAME="26614"></A>
<UL><PRE>  <i>do whatever is necessary to place an encrypted
  version of</i> password <i>in</i> encrypted;
</PRE>
</UL><A NAME="26615"></A>
<UL><PRE>  return encrypted;
}
</PRE>
</UL><A NAME="26610"></A>
<P><A NAME="dingp81"></A>
This code still isn't as tight as it might be, because <CODE>encrypted</CODE> is defined without any initialization arguments. That means its default constructor will be used. In many cases, the first thing you'll do to an object is give it some value, often via an assignment. <A HREF="./EC3_FR.HTM#2071" TARGET="_top">Item 12</A> explains why default-constructing an object and then assigning to it is a lot less efficient than initializing it with the value you really want it to have. That analysis applies here, too. For example, suppose the hard part of <CODE>encryptPassword</CODE> is performed in this <NOBR>function:<SCRIPT>create_link(81);</SCRIPT>
</NOBR></P>
<A NAME="26644"></A>
<UL><PRE>
void encrypt(string&amp; s);      // encrypts s in place
</PRE>
</UL><A NAME="26647"></A>
<P><A NAME="dingp82"></A>
Then <CODE>encryptPassword</CODE> could be implemented like this, though it wouldn't be the best way to do <NOBR>it:<SCRIPT>create_link(82);</SCRIPT>
</NOBR></P>
<A NAME="26650"></A>
<UL><PRE>// this function postpones "encrypted"'s definition until
// it's necessary, but it's still needlessly inefficient
string encryptPassword(const string&amp; password)
{
  ...                      // check length as above
</PRE>
</UL><A NAME="26651"></A>
<UL><PRE>
  string encrypted;        // default-construct encrypted
  encrypted = password;    // assign to encrypted
  encrypt(encrypted);
  return encrypted;
}
</PRE>
</UL><A NAME="26648"></A>
<P><A NAME="dingp83"></A>
A preferable approach is to initialize <CODE>encrypted</CODE> with <CODE>password</CODE>, thus skipping the (pointless) default <NOBR>construction:<SCRIPT>create_link(83);</SCRIPT>
</NOBR></P>
<A NAME="26668"></A>
<P>
<UL><PRE>// finally, the best way to define and initialize encrypted
string encryptPassword(const string&amp; password)
{
  ...                             // check length
</PRE>
</UL><A NAME="26669"></A>
<UL><PRE>
  string encrypted(password);     // define and initialize
                                  // via copy constructor
</PRE>
</UL><A NAME="26684"></A>
<UL><PRE>  encrypt(encrypted);
  return encrypted;
}
</PRE>
</UL><A NAME="26631"></A>
<P><A NAME="dingp84"></A>
<A NAME="p137"></A>This suggests the real meaning of "as long as possible" in this Item's title. Not only should you postpone a variable's definition until right before you have to use the variable, you should try to postpone the definition until you have initialization arguments for it. By doing so, you avoid not only constructing and destructing unneeded objects, you also avoid pointless default constructions. Further, you help document the purpose of variables by initializing them in contexts in which their meaning is clear. Remember how in C you're encouraged to put a short comment after each variable definition to explain what the variable will eventually be used for? Well, combine decent variable names (see also <A HREF="./EC4_FR.HTM#6429" TARGET="_top">Item 28</A>) with contextually meaningful initialization arguments, and you have every programmer's dream: a solid argument for <I>eliminating</I> some <NOBR>comments.<SCRIPT>create_link(84);</SCRIPT>
</NOBR></P>
<A NAME="26727"></A>
<P><A NAME="dingp85"></A>
By postponing variable definitions, you improve program efficiency, increase program clarity, and reduce the need to document variable meanings. It looks like it's time to kiss those block-opening variable definitions <NOBR>good-bye.<SCRIPT>create_link(85);</SCRIPT>
</NOBR></P>
<!-- SectionName="E33: Use inlining judiciously" -->
<A NAME="25939"></A><A NAME="6729"></A><A NAME="6730"></A>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="#25939">Item 32: Postpone variable definitions as long as possible.</A>
                            <BR>Continue to <A HREF="#6793">Item 34: Minimize compilation dependencies between files.</A></FONT></DIV>


<P><A NAME="dingp86"></A><FONT ID="eititle">Item 33: &nbsp;Use inlining judiciously.</FONT><SCRIPT>create_link(86);</SCRIPT>
</P>

<P><A NAME="dingp87"></A>
Inline functions -- what a <I>wonderful</I> idea! They look like functions, they act like functions, they're ever so much better than macros (see <A HREF="./EC1_FR.HTM#1790" TARGET="_top">Item 1</A>), and you can call them without having to incur the overhead of a function call. What more could you possibly ask <NOBR>for?<SCRIPT>create_link(87);</SCRIPT>
</NOBR></P>
<A NAME="6735"></A>
<P><A NAME="dingp88"></A>
You actually get more than you might think, because avoiding the cost of a function call is only half the story. Compiler optimization routines are typically designed to concentrate on stretches of code that lack function calls, so when you inline a function, you may enable compilers to perform context-specific optimizations on the body of the function. Such optimizations would be impossible for "normal" function <NOBR>calls.<SCRIPT>create_link(88);</SCRIPT>

⌨️ 快捷键说明

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