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

📄 chapter09.html

📁 《C++编程思想》中文版。。。。。。。。。。。。。
💻 HTML
📖 第 1 页 / 共 5 页
字号:
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; oldBytes; i++)
    b[i] = storage[i]; <font color=#009900>// Copy old to new</font>
  <font color=#0000ff>delete</font> [](storage); <font color=#009900>// Release old storage</font>
  storage = b; <font color=#009900>// Point to new memory</font>
  quantity = newQuantity; <font color=#009900>// Adjust the size</font>
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Once again, the test program verifies
that everything is working correctly:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C09:Stash4Test.cpp</font>
<font color=#009900>//{L} Stash4</font>
#include <font color=#004488>"Stash4.h"</font>
#include <font color=#004488>"../require.h"</font>
#include &lt;fstream&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main() {
  Stash intStash(<font color=#0000ff>sizeof</font>(<font color=#0000ff>int</font>));
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 100; i++)
    intStash.add(&amp;i);
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> j = 0; j &lt; intStash.count(); j++)
    cout &lt;&lt; <font color=#004488>"intStash.fetch("</font> &lt;&lt; j &lt;&lt; <font color=#004488>") = "</font>
         &lt;&lt; *(<font color=#0000ff>int</font>*)intStash.fetch(j)
         &lt;&lt; endl;
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> bufsize = 80;
  Stash stringStash(<font color=#0000ff>sizeof</font>(<font color=#0000ff>char</font>) * bufsize, 100);
  ifstream in(<font color=#004488>"Stash4Test.cpp"</font>);
  assure(in, <font color=#004488>"Stash4Test.cpp"</font>);
  string line;
  <font color=#0000ff>while</font>(getline(in, line))
    stringStash.add((<font color=#0000ff>char</font>*)line.c_str());
  <font color=#0000ff>int</font> k = 0;
  <font color=#0000ff>char</font>* cp;
  <font color=#0000ff>while</font>((cp = (<font color=#0000ff>char</font>*)stringStash.fetch(k++))!=0)
    cout &lt;&lt; <font color=#004488>"stringStash.fetch("</font> &lt;&lt; k &lt;&lt; <font color=#004488>") = "</font>
         &lt;&lt; cp &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This is the same test program that was
used before, so the output should be basically the same.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>Stack</B> class makes even better
use of inlines: <A NAME="Index1646"></A></FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C09:Stack4.h</font>
<font color=#009900>// With inlines</font>
#ifndef STACK4_H
#define STACK4_H
#include <font color=#004488>"../require.h"</font>

<font color=#0000ff>class</font> Stack {
  <font color=#0000ff>struct</font> Link {
    <font color=#0000ff>void</font>* data;
    Link* next;
    Link(<font color=#0000ff>void</font>* dat, Link* nxt): 
      data(dat), next(nxt) {}
  }* head;
<font color=#0000ff>public</font>:
  Stack() : head(0) {}
  ~Stack() {
    require(head == 0, <font color=#004488>"Stack not empty"</font>);
  }
  <font color=#0000ff>void</font> push(<font color=#0000ff>void</font>* dat) {
    head = <font color=#0000ff>new</font> Link(dat, head);
  }
  <font color=#0000ff>void</font>* peek() <font color=#0000ff>const</font> { 
    <font color=#0000ff>return</font> head ? head-&gt;data : 0;
  }
  <font color=#0000ff>void</font>* pop() {
    <font color=#0000ff>if</font>(head == 0) <font color=#0000ff>return</font> 0;
    <font color=#0000ff>void</font>* result = head-&gt;data;
    Link* oldHead = head;
    head = head-&gt;next;
    <font color=#0000ff>delete</font> oldHead;
    <font color=#0000ff>return</font> result;
  }
};
#endif <font color=#009900>// STACK4_H ///:~</font></PRE></FONT></BLOCKQUOTE>


<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice that the <B>Link</B> destructor
that was present but empty in the previous version of <B>Stack </B>has been
removed. In <B>pop(&#160;)</B>, the expression <B>delete oldHead</B> simply
releases the memory used by that <B>Link </B>(it does not destroy the <B>data
</B>object pointed to by the <B>Link</B>).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Most of the functions inline quite nicely
and obviously, especially for <B>Link</B>. Even <B>pop(&#160;)</B> seems
legitimate, although anytime you have conditionals or local variables it&#8217;s
not clear that inlines will be that beneficial. Here, the function is small
enough that it probably won&#8217;t hurt anything.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If all your functions <I>are</I> inlined,
using the library becomes quite simple because there&#8217;s no linking
necessary, as you can see in the test example (notice that there&#8217;s no
<B>Stack4.cpp</B>):</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C09:Stack4Test.cpp</font>
<font color=#009900>//{T} Stack4Test.cpp</font>
#include <font color=#004488>"Stack4.h"</font>
#include <font color=#004488>"../require.h"</font>
#include &lt;fstream&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main(<font color=#0000ff>int</font> argc, <font color=#0000ff>char</font>* argv[]) {
  requireArgs(argc, 1); <font color=#009900>// File name is argument</font>
  ifstream in(argv[1]);
  assure(in, argv[1]);
  Stack textlines;
  string line;
  <font color=#009900>// Read file and store lines in the stack:</font>
  <font color=#0000ff>while</font>(getline(in, line))
    textlines.push(<font color=#0000ff>new</font> string(line));
  <font color=#009900>// Pop the lines from the stack and print them:</font>
  string* s;
  <font color=#0000ff>while</font>((s = (string*)textlines.pop()) != 0) {
    cout &lt;&lt; *s &lt;&lt; endl;
    <font color=#0000ff>delete</font> s; 
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">People will sometimes write classes with
all inline functions so that the whole class will be in the header file
(you&#8217;ll see in this book that I step over the line myself). During program
development this is probably harmless, although sometimes it can make for longer
compilations. Once the program stabilizes a bit, you&#8217;ll probably want to
go back and make functions non-inline where
appropriate.</FONT><A NAME="_Toc472654904"></A><BR></P></DIV>
<A NAME="Heading285"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Inlines &amp; the compiler</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To understand when inlining
<A NAME="Index1647"></A>is effective, it&#8217;s helpful to know what the
compiler does when it encounters an inline. As with any function, the compiler
holds the function <I>type<A NAME="Index1648"></A><A NAME="Index1649"></A></I>
(that is, the function prototype including the name and argument types, in
combination with the function return value) in its symbol table. In addition,
when the compiler sees that the inline&#8217;s function type <I>and</I> the
function body parses without error, the code for the function body is also
brought into the symbol table. Whether the code is stored in source form,
compiled assembly instructions, or some other representation is up to the
compiler.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When you make a call to an inline
function, the compiler first ensures that the call can be correctly made. That
is, all the argument types must either be the exact types in the
function&#8217;s argument list, or the compiler must be able to make a type
conversion to the proper types and the return value must be the correct type (or
convertible to the correct type) in the destination expression. This, of course,
is exactly what the compiler does for any function and is markedly different
from what the preprocessor does because the preprocessor cannot check types or
make conversions.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If all the function type information fits
the context of the call, then the inline code is substituted directly for the
function call, eliminating the call overhead and allowing for further
optimizations by the compiler. Also, if the inline is a member function, the
address of the object (<B>this</B>) is put in the appropriate place(s), which of
course is another action the preprocessor is unable to
perform.</FONT><A NAME="_Toc312373931"></A><A NAME="_Toc472654905"></A><BR></P></DIV>
<A NAME="Heading286"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Limitations<BR><A NAME="Index1650"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There are two situations in which the
compiler cannot perform inlining. In these cases, it simply reverts to the
ordinary form of a function by taking the inline definition and creating storage
for the function just as it does for a non-inline. If it must do this in
multiple translation units (which would normally cause a multiple definition
error), the linker is told to ignore the multiple definitions.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The compiler cannot perform inlining if
the function is too complicated. This depends upon the particular compiler, but
at the point most compilers give up, the inline probably wouldn&#8217;t gain you
any efficiency. In general, any sort of looping is considered too complicated to
expand as an inline, and if you think about it, looping probably entails much
more time inside the function than what is required for the function call
overhead. If the function is just a collection of simple statements, the
compiler probably won&#8217;t have any trouble inlining it, but if there are a
lot of statements, the overhead of the function call will be much less than the
cost of executing the body. And remember, every time you call a big inline
function, the entire function body is inserted in place of each call, so you can
easily get <A NAME="Index1651"></A><A NAME="Index1652"></A>code bloat without
any noticeable performance improvement. (Note that some of the examples in this
book may exceed reasonable inline sizes in favor of conserving screen real
estate.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The compiler also cannot perform inlining
if the <A NAME="Index1653"></A><A NAME="Index1654"></A>address of the function
is taken implicitly or explicitly. If the compiler must produce an address, then
it will allocate storage for the function code and use the resulting address.
However, where an address is not required, the compiler will probably still
inline the code.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It is important to understand that an
inline is just a suggestion to the compiler; the compiler is not forced to
inline anything at all. A good compiler will inline small, simple functions
while intelligently ignoring inlines that are too complicated. This will give
you the results you want &#8211; the true semantics of a function call with the
efficiency of a macro.</FONT><A NAME="_Toc472654906"></A><BR></P></DIV>
<A NAME="Heading287"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Forward references</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you&#8217;re imagining what the
compiler is doing to implement inlines, you can confuse yourself into thinking
there are more limitations than actually exist. In particular, if an inline
<A NAME="Index1655"></A><A NAME="Index1656"></A>makes a forward reference
<A NAME="Index1657"></A>to a function that hasn&#8217;t yet been declared in the
class (whether that function is inline or not), it can seem like the compiler
won&#8217;t be able to handle it:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C09:EvaluationOrder.cpp</font>
<font color=#009900>// Inline evaluation order</font>

<font color=#0000ff>class</font> Forward {
  <font color=#0000ff>int</font> i;
<font color=#0000ff>public</font>:
  Forward() : i(0) {}
  <font color=#009900>// Call to undeclared function:</font>
  <font color=#0000ff>int</font> f() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> g() + 1; }
  <font color=#0000ff>int</font> g() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> i; }
};

<font color=#0000ff>int</font> main() {
  Forward frwd;
  frwd.f();
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>f(&#160;)</B>, a call is made to
<B>g(&#160;)</B>, although <B>g(&#160;)</B> has not yet been declared. This
works because the language definition states that no inline functions in a class
shall be evaluated until the closing brace of the class
declaration.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course, if <B>g(&#160;)</B> in turn
called <B>f(&#160;)</B>, you&#8217;d end up with a set of recursive calls, which
are too complicated for the compiler to inline. (Also, you&#8217;d have to
perform some test in <B>f(&#160;)</B> or <B>g(&#160;)</B> to force one of them
to &#8220;bottom out,&#8221; or the <A NAME="Index1658"></A>recursion would be

⌨️ 快捷键说明

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