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

📄 ec2.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 5 页
字号:
Finally, <CODE>X</CODE>'s <CODE>operator</CODE> <CODE>new</CODE> will do the <NOBR>following:<SCRIPT>create_link(50);</SCRIPT>
</NOBR></p>
<A NAME="29204"></A><OL TYPE="1"><A NAME="dingp51"></A><LI>Call the standard <CODE>set_new_handler</CODE> with <CODE>X</CODE>'s error-handling
function. This will install <CODE>X</CODE>'s new-handler as the global new-
handler. In the code below, notice how you explicitly reference
the <CODE>std</CODE> scope (where the standard <CODE>set_new_handler</CODE> resides)
by using the "<CODE>::</CODE>" notation.<SCRIPT>create_link(51);</SCRIPT>

<A NAME="29220"></A><A NAME="dingp52"></A><LI>Call the global <CODE>operator</CODE> <CODE>new</CODE> to actually allocate the requested memory. If the initial attempt at allocation fails, the global <CODE>operator</CODE> <CODE>new</CODE> will invoke <CODE>X</CODE>'s new-handler, because that function was just installed as the global new-handler. If the global <CODE>operator</CODE> <CODE>new</CODE> is ultimately unable to find a way to allocate the requested memory, it will throw a <CODE>std::bad_alloc</CODE> exception, which <CODE>X</CODE>'s <CODE>operator</CODE> <CODE>new</CODE> will catch. <CODE>X</CODE>'s <CODE>operator</CODE> <CODE>new</CODE> will then restore the global new-handler that was originally in place, and it will return by propagating the exception.<SCRIPT>create_link(52);</SCRIPT>

<A NAME="29259"></A><A NAME="dingp53"></A><LI>Assuming the global <CODE>operator</CODE> <CODE>new</CODE> was able to successfully allocate enough memory for an object of type <CODE>X</CODE>, <CODE>X</CODE>'s <CODE>operator</CODE> <CODE>new</CODE> will again call the standard <CODE>set_new_handler</CODE> to restore the global error-handling function to what it was originally. It will then return a pointer to the allocated memory.<SCRIPT>create_link(53);</SCRIPT>

</OL>
<A NAME="29254"></A>
<A NAME="dingp54"></A>Here's how you say all that in <NOBR>C++:<SCRIPT>create_link(54);</SCRIPT>
</NOBR></P>
<A NAME="1936"></A>
<UL><PRE>
void * X::operator new(size_t size)
{
  new_handler globalHandler =                // install X's
    std::set_new_handler(currentHandler);    // handler
</PRE>
</UL><A NAME="13310"></A>
<UL><PRE>
  void *memory;
</PRE>
</UL><A NAME="29189"></A>
<UL><PRE>
  try {                                      // attempt
    memory = ::operator new(size);           // allocation
  }
  catch (std::bad_alloc&amp;) {                  // restore
    std::set_new_handler(globalHandler);     // handler;
    throw;                                   // propagate
  }                                          // exception
</PRE>
</UL><A NAME="13313"></A>
<UL><PRE><A NAME="p31"></A>
  std::set_new_handler(globalHandler);       // restore
                                             // handler
  return memory;
}
</PRE>
</UL><A NAME="13317"></A>
<P><A NAME="dingp55"></A>
If the duplicated calls to <CODE>std::set_new_handler</CODE> caught your eye, turn to <A HREF="../MEC/MC3_FR.HTM#5292" TARGET="_top">Item M9</A> for information on how to eliminate <NOBR>them.<SCRIPT>create_link(55);</SCRIPT>
</NOBR></P>
<A NAME="222012"></A>
<P><A NAME="dingp56"></A>
Clients of class <CODE>X</CODE> use its new-handling capabilities like <NOBR>this:<SCRIPT>create_link(56);</SCRIPT>
</NOBR></P>
<A NAME="13319"></A>
<UL><PRE>
void noMoreMemory();                           // decl. of function to
                                               // call if memory allocation
                                               // for X objects fails
</PRE>
</UL><A NAME="13320"></A>
<UL><PRE>
X::set_new_handler(noMoreMemory);
                                               // set noMoreMemory as X's
                                               // new-handling function
</PRE>
</UL><A NAME="13321"></A>
<UL><PRE>
X *px1 = new X;                                // if memory allocation
                                               // fails, call noMoreMemory
</PRE>
</UL><A NAME="13328"></A>
<UL><PRE>
string *ps = new string;                       // if memory allocation
                                               // fails, call the global
                                               // new-handling function
                                               // (if there is one)
</PRE>
</UL><A NAME="13322"></A>
<UL><PRE>
X::set_new_handler(0);                         // set the X-specific
                                               // new-handling function
                                               // to nothing (i.e., null)
</PRE>
</UL><A NAME="13323"></A>
<UL><PRE>
X *px2 = new X;                                // if memory allocation
                                               // fails, throw an exception
                                               // immediately. (There is
                                               // no new-handling function
                                               // for class X.)
</PRE>
</UL><A NAME="1938"></A>
<P><A NAME="dingp57"></A>
You may note that the code for implementing this scheme is the same regardless of the class, so a reasonable inclination would be to reuse it in other places. As <A HREF="./EC6_FR.HTM#7611" TARGET="_top">Item 41</A> explains, both inheritance and templates can be used to create reusable code. However, in this case, it's a combination of the two that gives you what you <NOBR>need.<SCRIPT>create_link(57);</SCRIPT>
</NOBR></P>
<A NAME="13352"></A>
<P><A NAME="dingp58"></A>
All you have to do is create a "mixin-style" base class, i.e., a base class that's designed to allow derived classes to inherit a single specific capability &#151; in this case, the ability to set a class-specific new-handler. Then you turn the base class into a template. The base class part of the design lets derived classes inherit the <CODE>set_new_handler</CODE> and <CODE>operator</CODE> <CODE>new</CODE> functions they all need, while the template part of the design ensures that each inheriting class gets a different <CODE>currentHandler</CODE> data member. The result may sound a little complicated, but you'll find that the code looks reassuringly familiar. In fact, about the only real difference is that it's now reusable by any class that wants <NOBR>it:<SCRIPT>create_link(58);</SCRIPT>
</NOBR></P>
<A NAME="13379"></A>
<UL><PRE><A NAME="p32"></A>
template&lt;class T&gt;				// "mixin-style" base class
class NewHandlerSupport {			// for class-specific
public:						// set_new_handler support
</PRE>
</UL><A NAME="13414"></A>
<UL><PRE>
  static new_handler set_new_handler(new_handler p);
  static void * operator new(size_t size);
</PRE>
</UL><A NAME="13385"></A>
<UL><PRE>private:
  static new_handler currentHandler;
};
</PRE>
</UL><A NAME="13404"></A>
<UL><PRE>template&lt;class T&gt;
new_handler NewHandlerSupport&lt;T&gt;::set_new_handler(new_handler p)
{
  new_handler oldHandler = currentHandler;
  currentHandler = p;
  return oldHandler;
}
</PRE>
</UL><A NAME="29269"></A>
<UL><PRE>template&lt;class T&gt;
void * NewHandlerSupport&lt;T&gt;::operator new(size_t size)
{
  new_handler globalHandler =
    std::set_new_handler(currentHandler);
</PRE>
</UL><A NAME="29270"></A>
<UL><PRE>  void *memory;
</PRE>
</UL><A NAME="29281"></A>
<UL><PRE>  try {
    memory = ::operator new(size);
  }
  catch (std::bad_alloc&amp;) {
    std::set_new_handler(globalHandler);
    throw;
  }
</PRE>
</UL><A NAME="13421"></A>
<UL><PRE>  std::set_new_handler(globalHandler);
</PRE>
</UL><A NAME="29286"></A>
<UL><PRE>  return memory;
}
</PRE>
</UL><A NAME="31667"></A>
<UL><PRE>// this sets each currentHandler to 0
template&lt;class T&gt;
new_handler NewHandlerSupport&lt;T&gt;::currentHandler;
</PRE>
</UL><A NAME="13401"></A>
<P><A NAME="dingp59"></A>
With this class template, adding <CODE>set_new_handler</CODE> support to class <CODE>X</CODE> is easy: <CODE>X</CODE> just inherits from <CODE>newHandlerSupport&lt;X&gt;</CODE>:<SCRIPT>create_link(59);</SCRIPT>
</P>
<A NAME="13443"></A>
<UL><PRE>// note inheritance from mixin base class template. (See
// <A HREF="../MAGAZINE/CO_FRAME.HTM" TARGET="_top">my article on counting objects</a> for information on why
// private inheritance might be preferable here.)
class X: public NewHandlerSupport&lt;X&gt; {
</PRE>
</UL><A NAME="13444"></A>
<UL><PRE>
  ...                 // as before, but no declarations for
};                    // set_new_handler or operator new
</PRE>
</UL><A NAME="13446"></A>
<P><A NAME="dingp60"></A>
<A NAME="p33"></A>Clients of <CODE>X</CODE> remain oblivious to all the behind-the-scenes action; their old code continues to work. This is good, because one thing you can usually rely on your clients being is <NOBR>oblivious.<SCRIPT>create_link(60);</SCRIPT>
</NOBR></P>
<A NAME="13491"></A>
<P><A NAME="dingp61"></A>
Using <CODE>set_new_handler</CODE> is a convenient, easy way to cope with the possibility of out-of-memory conditions. Certainly it's a lot more attractive than wrapping every use of <CODE>new</CODE> inside a <CODE>try</CODE> block. Furthermore, templates like <CODE>NewHandlerSupport</CODE> make it simple to add a class-specific new-handler to any class that wants one. Mixin-style inheritance, however, invariably leads to the topic of multiple inheritance, and before starting down that slippery slope, you'll definitely want to read <A HREF="./EC6_FR.HTM#7778" TARGET="_top">Item 43</A>.<SCRIPT>create_link(61);</SCRIPT>
</P>
<A NAME="13563"></A>
<P><A NAME="dingp62"></A>
Until 1993, C++ required that <CODE>operator</CODE> <CODE>new</CODE> return 0 when it was unable to satisfy a memory request. The current behavior is for <CODE>operator</CODE> <CODE>new</CODE> to throw a <CODE>std::bad_alloc</CODE> exception, but a lot of C++ was written before compilers began supporting the revised specification. The <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>&deg;</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=committee" onMouseOver = "self.status = 'ISO ANSI Standardization Committee'; return true" onMouseOut = "self.status = self.defaultStatus" TARGET="_top">C++</NOBR> standardization committee</A> didn't want to abandon the established test-for-0 code base, so they provided alternative forms of <CODE>operator</CODE> <CODE>new</CODE> (and <CODE>operator</CODE> <CODE><NOBR>new[]</NOBR></CODE> &#151; see <A HREF="#120851">Item 8</A>) that continue to offer the traditional failure-yields-0 behavior. These forms are called "nothrow" forms because, well, they never do a <CODE>throw</CODE>, and they employ <CODE>nothrow</CODE> objects (defined in the standard header <CODE>&lt;new&gt;</CODE>) at the point where <CODE>new</CODE> is <NOBR>used:<SCRIPT>create_link(62);</SCRIPT>
</NOBR></P>
<A NAME="13763"></A>
<UL><PRE>class Widget { ... };
</PRE>
</UL><A NAME="31673"></A>
<UL><PRE>
Widget *pw1 = new Widget;      // throws std::bad_alloc if

⌨️ 快捷键说明

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