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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 1 页 / 共 5 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>

<HEAD>
	<META NAME="Author" Content="Steph Mineart">
	<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">
	<TITLE>ANSI/ISO C++ Professional Programmer's Handbook - Chapter 12 - Optimizing Your Code</TITLE>
	<link rel="stylesheet"  TYPE="text/css" href="/includes/stylesheets/ebooks.css">
</head>

<BODY TEXT="#000000" BGCOLOR="#FFFFFF">

<CENTER>
<H1><img src="/publishers/que/series/professional/0789720221/button/que.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM" BORDER="0"><BR>
ANSI/ISO C++ Professional Programmer's Handbook</H1>
</CENTER>
<CENTER>
  <P><A HREF="/publishers/que/series/professional/0789720221/index.htm"><img src="/publishers/que/series/professional/0789720221/button/contents.gif" WIDTH="128"
HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A> 
  <HR>
</CENTER>
<H1 align="center">12</H1>
<h1 align="center"> Optimizing Your Code</h1>
<address>by Danny Kalev </address>
<ul>
  <li><a href="#Heading1">Introduction</a> 
    <ul>
      <li><a href="#Heading2">Scope of This Chapter</a> 
    </ul>
  <li><a href="#Heading3">Before Optimizing Your Software</a> 
  <li><a href="#Heading4">Declaration Placement</a> 
    <ul>
      <li><a href="#Heading5">Prefer Initialization to Assignment</a> 
      <li><a href="#Heading6">Relocating Declarations</a> 
      <li><a href="#Heading7">Member-Initialization Lists</a> 
      <li><a href="#Heading8">Prefix Versus Postfix Operators </a> 
    </ul>
  <li><a href="#Heading9">Inline Functions</a> 
    <ul>
      <li><a href="#Heading10">Function Call Overhead</a> 
      <li><a href="#Heading11">Benefits of Inline Functions</a> 
      <li><a href="#Heading12">What Happens When a Function that Is Declared inline 
        Cannot Be Inlined?</a> 
      <li><a href="#Heading13">Additional Issues of Concern</a> 
      <li><a href="#Heading14">The Do's and Don'ts of inline</a> 
    </ul>
  <li><a href="#Heading15">Optimizing Memory Usage</a> 
    <ul>
      <li><a href="#Heading16">Bit Fields</a> 
      <li><a href="#Heading17">Unions</a> 
    </ul>
  <li><a href="#Heading18">Speed Optimizations</a> 
    <ul>
      <li><a href="#Heading19">Using a Class To Pack a Long Argument List</a> 
      <li><a href="#Heading20">Register Variables</a> 
      <li><a href="#Heading21">Declaring Constant Objects as const</a> 
      <li><a href="#Heading22">Runtime Overhead of Virtual Functions </a> 
      <li><a href="#Heading23">Function Objects Versus Function Pointers</a> 
    </ul>
  <li><a href="#Heading24">A Last Resort</a> 
    <ul>
      <li><a href="#Heading25">Disabling RTTI and Exception Handling Support</a> 
      <li><a href="#Heading26">Inline Assembly</a> 
      <li><a href="#Heading27">Interacting with the Operating System Directly</a> 
    </ul>
  <li><a href="#Heading28">Conclusions</a> 
</ul>
<hr size=4>
<h2><a name="Heading1"> Introduction</a></h2>
<p>One often-heard claim during the past 30 years is that performance doesn't 
  matter because the computational power of hardware is constantly dropping. Therefore, 
  buying a stronger machine or extending the RAM of an existing one can make up 
  for the sluggish performance of software written in a high-level programming 
  language. In other words, a hardware upgrade is more cost-effective than the 
  laborious task of hand-tuning code. That might be correct for client applications 
  that execute on a standard personal computer. A modestly priced personal computer 
  these days offers higher computational power than a mainframe did two decades 
  ago, and the computational power still grows exponentially every 18 months or 
  so. However, in many other application domains, a hardware upgrade is less favorable 
  because it is too expensive or because it simply is not an option. In proprietary 
  embedded systems with 128K of RAM or less, extending the RAM requires redesigning 
  the entire system from scratch, as well as investing several years in the development 
  and testing of the new chips. In this case, code optimization is the only viable 
  choice for satisfactory performance.</p>
<p>But optimization is not confined to esoteric application domains such as embedded 
  systems or hard core real-time applications. Even in mainstream application 
  domains such as financial and billing systems, code optimization is sometimes 
  necessary. For a bank that owns a $1,500,000 mainframe computer, buying a faster 
  machine is less preferable than rewriting a few thousand lines of critical code. 
  Code optimization is also the primary tool for achieving satisfactory performance 
  from server applications that support numerous users, such as Relational Database 
  Management Systems and Web servers.</p>
<p>Another common belief is that code optimization implies less readable and harder 
  to maintain software. This is not necessarily true. Sometimes, simple code modifications 
  such as relocating the declarations in a source file or choosing a different 
  container type can make all the difference in the world. Yet none of these changes 
  entails unreadable code, nor do they incur any additional maintenance overhead. 
  In fact, some of the optimization techniques can even improve the software's 
  extensibility and readability. More aggressive optimizations can range from 
  using a simplified class hierarchy, through the combination of inline assembly 
  code. The result in this case is less readable, harder to maintain, and less 
  portable code. Optimization can be viewed as a continuum; the extent to which 
  it is applied depends on a variety of considerations.</p>
<h3> <a name="Heading2"> Scope of This Chapter</a></h3>
<p>Optimization is a vast subject that can easily fill a few thick volumes. This 
  chapter discusses various optimization techniques, most of which can be easily 
  applied in C++ code without requiring a deep understanding of the underlying 
  hardware architecture of a particular platform. The intent is to give you a 
  rough estimate of the performance cost of choosing one programming strategy 
  over another (you can experiment with the programs that are discussed in the 
  following sections on your computer). The purpose is to provide you with practical 
  guidelines and notions, rather than delve into theoretical aspects of performance 
  analysis, efficiency of algorithms, or the Big Oh notation. </p>
<h2> <a name="Heading3"> Before Optimizing Your Software</a></h2>
<p>Detecting the bottlenecks of a program is the first step in optimizing it. 
  It is important, however, to profile the release version rather than the debug 
  version of the program because the debug version of the executable contains 
  additional code. A debug-enabled executable can be about 40% larger than the 
  equivalent release executable. The extra code is required for symbol lookup 
  and other debug "scaffolding". Most implementations provide distinct debug and 
  release versions of operator <tt>new</tt> and other library functions. Usually, 
  the debug version of <tt>new</tt> initializes the allocated memory with a unique 
  value and adds a header at block start; the release version of <tt>new</tt> 
  doesn't perform either of these tasks. Furthermore, a release version of an 
  executable might have been optimized already in several ways, including the 
  elimination of unnecessary temporary objects, loop unrolling (see the sidebar 
  "A Few Compiler Tricks"), moving objects to the registers, and inlining. For 
  these reasons, you cannot assuredly deduce from a debug version where the performance 
  bottlenecks are actually located.</p>
<blockquote> 
  <hr>
  <b>A Few Compiler Tricks</b> 
  <p> A compiler can automatically optimize the code in several ways. The <i>named 
    return value</i> and <i>loop unrolling</i> are two instances of such automatic 
    optimizations.</p>
  <p> Consider the following code:</p>
  <pre>
<tt>  int *buff = new int[3];</tt>
<tt>  for (int i =0; i&lt;3; i++)</tt>
<tt>    buff[i] = 0;</tt>
</pre>
  <p> This loop is inefficient: On every iteration, it assigns a value to the 
    next array element. However, precious CPU time is also wasted on testing and 
    incrementing the counter's value and performing a jump statement. To avoid 
    this overhead, the compiler can unroll the loop into a sequence of three assignment 
    statements, as follows: </p>
  <pre>
<tt>  buff[0] = 0; </tt>
<tt>  buff[1] = 0; </tt>
<tt>  buff[2] = 0; </tt>
  </pre>
  The named return value is a C++-specific optimization that eliminates the construction 
  and destruction of a temporary object. When a temporary object is copied to 
  another object using a copy constructor, and when both these objects are cv-unqualified, 
  the Standard allows the implementation to treat the two objects as one, and 
  not perform a copy at all. For example 
  <pre>
<tt>class A</tt>
<tt>{</tt>
<tt>public:</tt>
<tt>  A();</tt>
<tt>  ~A();</tt>
<tt>  A(const A&amp;);</tt>
<tt>  A operator=(const A&amp;);</tt>
<tt>};</tt>
<tt>A f() </tt>
<tt>{</tt>
<tt>  A a;</tt>
<tt>  return a;</tt>
<tt>}</tt>
<tt>A a2 = f();</tt>
  </pre>
  The object <tt>a</tt> does not need to be copied when <tt>f()</tt> returns. 
  Instead, the return value of <tt>f()</tt> can be constructed directly into the 
  object <tt>a2</tt>, thereby avoiding both the construction and destruction of 
  a temporary object on the stack. 
  <hr>
</blockquote>
<p>Remember also that debugging and optimization are two distinct operations. 
  The debug version needs to be used to trap bugs and to verify that the program 
  is free from logical errors. The tested release version needs to be used in 
  performance tuning and optimizations. Of course, applying the code optimization 
  techniques that are presented in this chapter can enhance the performance of 
  the debug version as well, but the release version is the one that needs to 
  be used for performance evaluation.</p>
<blockquote>
  <hr>
  <strong>NOTE: </strong> It is not uncommon to find a "phantom bottleneck" in 
  the debug version, which the programmer strains hard to fix, only to discover 
  later that it has disappeared anyway in the release version. Andrew Koenig wrote 
  an excellent article that tells the story of an evasive bottleneck that automatically 
  dissolved in the release version ("An Example of Hidden Library Overhead", <i>C++ 
  Report</i> vol. 10:2, February 1998, page 11). The lesson that can be learned 
  from this article is applicable to everyone who practices code optimization. 
  <hr>
</blockquote>
<h2> <a name="Heading4"> Declaration Placement</a></h2>
<p>The placing of declarations of variables and objects in the program can have 
  significant performance effects. Likewise, choosing between the postfix and 
  prefix operators can also affect performance. This section concentrates on four 
  issues: initialization versus assignment, relocation of declarations to the 
  part of the program that actually uses them, a constructor's member initialization 
  list, and prefix versus postfix operators.</p>
<h3> <a name="Heading5"> Prefer Initialization to Assignment</a></h3>
<p>C allows declarations only at a block's beginning, before any program statements. 
  For example</p>
<pre>
<tt>void f();</tt>
<tt>void g()</tt>
<tt>{</tt>
<tt>  int i; </tt>
<tt>  double d; </tt>
<tt>  char * p;</tt>
<tt>  f(); </tt>
<tt>}</tt>
</pre>
<p>In C++, a declaration is a statement; as such, it can appear almost anywhere 
  within the program. For example</p>
<pre>
<tt>void f();</tt>
<tt>void g()</tt>
<tt>{</tt>
<tt> int i; </tt>
<tt> f(); </tt>
<tt> double d; </tt>
<tt> char * p;</tt>
<tt>}</tt>
</pre>
<p>The motivation for this change in C++ was to allow for declarations of objects 
  right before they are used. There are two benefits to this practice. First, 
  this practice guarantees that an object cannot be tampered with by other parts 
  of the program before it has been used. When objects are declared at the block's 
  beginning and are used only 20 or 50 lines later, there is no such guarantee. 
  For instance, a pointer to an object that was allocated on the free store might 
  be accidentally deleted somewhere before it is actually used. Declaring the 
  pointer right before it is used, however, reduces the likelihood of such mishaps.</p>
<p>The second benefit in declaring objects right before their usage is the capability 
  to initialize them immediately with the desired value. For example</p>
<pre>
<tt>#include &lt;string&gt;</tt>
<tt>using namespace std;</tt>
<tt>void func(const string&amp; s)</tt>
<tt>{</tt>
<tt>  bool emp = s.empty(); //local declarations enables immediate initialization</tt>
<tt>}</tt>
</pre>
<p>For fundamental types, initialization is only marginally more efficient than 
  assignment; or it can be identical to late assignment in terms of performance. 
  Consider the following version of <tt>func()</tt>, which applies assignment 

⌨️ 快捷键说明

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