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

📄 8610.htm

📁 C++细节解释
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<p>c++不支持专门针对于类的new-handler函数,而且也不需要。你可以自己来实现它,只要在每个类中提供自己版本的set_new_handler和operator new。类的set_new_handler可以为类指定new-handler(就象标准的set_new_handler指定全局new-handler一样)。类的operator new则保证为类的对象分配内存时用类的new-handler取代全局new-handler。</p> 
<p>假设处理类x内存分配失败的情况。因为operator new对类型x的对象分配内存失败时,每次都必须调用出错处理函数,所以要在类里声明一个new_handler类型的静态成员。那么类x看起来会象这样:<br>&nbsp;&nbsp;&nbsp; class x {<br>&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static new_handler set_new_handler(new_handler p);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static void * operator new(size_t size);</p> 
<p>&nbsp;&nbsp;&nbsp; private:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static new_handler currenthandler;<br>&nbsp;&nbsp;&nbsp; };</p> 
<p>类的静态成员必须在类外定义。因为想借用静态对象的缺省初始化值0,所以定义x::currenthandler时没有去初始化。<br>new_handler x::currenthandler;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 缺省设置currenthandler为0(即null)</p> 
<p>类x中的set_new_handler函数会保存传给它的任何指针,并返回在调用它之前所保存的任何指针。这正是标准版本的set_new_handler所做的:<br>new_handler x::set_new_handler(new_handler p)<br>{<br>&nbsp; new_handler oldhandler = currenthandler;<br>&nbsp; currenthandler = p;<br>&nbsp; return oldhandler;<br>}</p> 
<p>最后看看x的operator new所做的:<br>1. 调用标准set_new_handler函数,输入参数为x的出错处理函数。这使得x的new-handler函数成为全局new-handler函数。注意下面的代码中,用了"::"符号显式地引用std空间(标准set_new_handler函数就存在于std空间)。</p> 
<p>2. 调用全局operator new分配内存。如果第一次分配失败,全局operator new会调用x的new-handler,因为它刚刚(见1.)被安装成为全局new-handler。如果全局operator new最终未能分配到内存,它抛出std::bad_alloc异常,x的operator new会捕捉到它。x的operator new然后恢复最初被取代的全局new-handler函数,最后以抛出异常返回。</p> 
<p>3. 假设全局operator new为类型x的对象分配内存成功,, x的operator new会再次调用标准set_new_handler来恢复最初的全局出错处理函数。最后返回分配成功的内存的指针。</p> 
<p>c++是这么做的:<br>void * x::operator new(size_t size)<br>{<br>&nbsp; new_handler globalhandler =&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 安装x的new_handler<br>&nbsp;&nbsp;&nbsp; std::set_new_handler(currenthandler);&nbsp;&nbsp;&nbsp; </p> 
<p>&nbsp; void *memory;</p> 
<p>&nbsp; try {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 尝试分配内存<br>&nbsp;&nbsp;&nbsp; memory = ::operator new(size);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp; }<br>&nbsp; catch (std::bad_alloc&amp;) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 恢复旧的new_handler<br>&nbsp;&nbsp;&nbsp; std::set_new_handler(globalhandler);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; throw;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 抛出异常<br>&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p> 
<p>&nbsp; std::set_new_handler(globalhandler);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 恢复旧的new_handler<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp; return memory;<br>}</p> 
<p>如果你对上面重复调用std::set_new_handler看不顺眼,可以参见条款m9来除去它们。</p> 
<p>使用类x的内存分配处理功能时大致如下:<br>void nomorememory();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // x的对象分配内存失败时调用的<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // new_handler函数的声明<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </p> 
<p>x::set_new_handler(nomorememory);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 把nomorememory设置为x的<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // new-handling函数</p> 
<p>x *px1 = new x;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 如内存分配失败,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 调用nomorememory</p> 
<p>string *ps = new string;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 如内存分配失败,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 调用全局new-handling函数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </p> 
<p>x::set_new_handler(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 设x的new-handling函数为空<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </p> 
<p>x *px2 = new x;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 如内存分配失败,立即抛出异常<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // (类x没有new-handling函数)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</p> 
<p>你会注意到,处理以上类似情况,如果不考虑类的话,实现代码是一样的,这就很自然地想到在别的地方也能重用它们。正如条款41所说明的,继承和模板可以用来设计可重用代码。在这里,我们把两种方法结合起来使用,从而满足了你的要求。</p> 
<p>你只要创建一个“混合风格”(mixin-style)的基类,这种基类允许子类继承它某一特定的功能——这里指的是建立一个类的new-handler的功能。之所以设计一个基类,是为了让所有的子类可以继承set_new_handler和operator new功能,而设计模板是为了使每个子类有不同的currenthandler数据成员。这听起来很复杂,不过你会看到代码其实很熟悉。区别只不过是它现在可以被任何类重用了。<br>template&lt;class t&gt;&nbsp;&nbsp;&nbsp;&nbsp;// 提供类set_new_handler支持的<br>class newhandlersupport {&nbsp;&nbsp;&nbsp;// “混合风格”的基类<br>public:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p> 
<p>&nbsp; static new_handler set_new_handler(new_handler p);<br>&nbsp; static void * operator new(size_t size);</p> 
<p>private:<br>&nbsp; static new_handler currenthandler;<br>};</p> 
<p>template&lt;class t&gt;<br>new_handler newhandlersupport&lt;t&gt;::set_new_handler(new_handler p)<br>{<br>&nbsp; new_handler oldhandler = currenthandler;<br>&nbsp; currenthandler = p;<br>&nbsp; return oldhandler;<br>}</p> 
<p>template&lt;class t&gt;<br>void * newhandlersupport&lt;t&gt;::operator new(size_t size)<br>{<br>&nbsp; new_handler globalhandler =<br>&nbsp;&nbsp;&nbsp; std::set_new_handler(currenthandler);</p> 
<p>&nbsp; void *memory;</p> 
<p>&nbsp; try {<br>&nbsp;&nbsp;&nbsp; memory = ::operator new(size);<br>&nbsp; }<br>&nbsp; catch (std::bad_alloc&amp;) {<br>&nbsp;&nbsp;&nbsp; std::set_new_handler(globalhandler);<br>&nbsp;&nbsp;&nbsp; throw;<br>&nbsp; }</p> 
<p>&nbsp; std::set_new_handler(globalhandler);</p> 
<p>&nbsp; return memory;<br>}</p> 
<p>// this sets each currenthandler to 0<br>template&lt;class t&gt;<br>new_handler newhandlersupport&lt;t&gt;::currenthandler;</p> 
<p>有了这个模板类,对类x加上set_new_handler功能就很简单了:只要让x从newhandlersupport&lt;x&gt;继承:<br>// note inheritance from mixin base class template. (see<br>// my article on counting objects for information on why<br>// private inheritance might be preferable here.)<br>class x: public newhandlersupport&lt;x&gt; {</p> 
<p>&nbsp; ...&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // as before, but no declarations for<br>};&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // set_new_handler or operator new</p> 
<p><br>使用x的时候依然不用理会它幕后在做些什么;老代码依然工作。这很好!那些你常不去理会的东西往往是最可信赖的。</p> 
<p>使用set_new_handler是处理内存不够情况下一种方便,简单的方法。这比把每个new都包装在try模块里当然好多了。而且,newhandlersupport这样的模板使得向任何类增加一个特定的new-handler变得更简单。“混合风格”的继承不可避免地将话题引入到多继承上去,在转到这个话题前,你一定要先阅读条款43。</p> 
<p>1993年前,c++一直要求在内存分配失败时operator new要返回0,现在则是要求operator new抛出std::bad_alloc异常。很多c++程序是在编译器开始支持新规范前写的。c++标准委员会不想放弃那些已有的遵循返回0规范的代码,所以他们提供了另外形式的operator new(以及operator new[]——见条款8)以继续提供返回0功能。这些形式被称为“无抛出”,因为他们没用过一个throw,而是在使用new的入口点采用了nothrow对象:<br>class widget { ... };</p> 
<p>widget *pw1 = new widget;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 分配失败抛出std::bad_alloc if</p> 
<p>if (pw1 == 0) ...&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 这个检查一定失败<br>widget *pw2 =<br>&nbsp; new (nothrow) widget;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 若分配失败返回0</p> 
<p>if (pw2 == 0) ...&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 这个检查可能会成功</p> 
<p>不管是用“正规”(即抛出异常)形式的new还是“无抛出”形式的new,重要的是你必须为内存分配失败做好准备。最简单的方法是使用set_new_handler,因为它对两种形式都有用。<br><br> 
</p> 
</DIV></div></div> 
 
</center></BODY></HTML> 

⌨️ 快捷键说明

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