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

📄 item_083.htm

📁 C++程序编写规范,适合C++中级读者
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<div class=Section1>

<h3><span lang=EN-US>83. </span><span style='font-family:宋体;mso-ascii-font-family:
Arial;mso-hansi-font-family:Arial'>使用一个带检查的(</span><span lang=EN-US>checked</span><span
style='font-family:宋体;mso-ascii-font-family:Arial;mso-hansi-font-family:Arial'>)</span><span
lang=EN-US>STL</span><span style='font-family:宋体;mso-ascii-font-family:Arial;
mso-hansi-font-family:Arial'>实现。</span></h3>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>摘要</span></b></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>安全为上(参见第</span><span lang=EN-US>6</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>条):即使只在某一个编译器平台上可用,即使只在发布前的测试中使用,也仍然要使用一个带检查的</span><span
lang=EN-US>STL</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>实现,</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>讨论</span><a name=ch75index09></a><a name=ch75index08></a><a
name=ch75lev1sec2></a><span lang=EN-US><o:p></o:p></span></b></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>正如指针错误,迭代器错误太容易犯了,并且通常会编译通过但然后崩溃(最好的情况)或看起来工作正常(最糟糕的情况)。即使编译器不能抓住错误,你不必,也不应该依赖于“靠眼睛来找到错误”:有这样的工具存在。应该使用它们。</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>有些</span><span lang=EN-US>STL</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>错误普遍存在,即使对有经验的程序员来说也是如此:</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<ul style='margin-top:0cm' type=disc>
 <li class=MsoNormal style='mso-list:l1 level1 lfo5;tab-stops:list 36.0pt'><i
     style='mso-bidi-font-style:normal'><span style='font-family:宋体;mso-ascii-font-family:
     "Times New Roman";mso-hansi-font-family:"Times New Roman"'>使用一个已作废的或未初始化的迭代器:</span></i><span
     style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
     "Times New Roman"'>前者在实践中很容易产生。</span></li>
</ul>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<ul style='margin-top:0cm' type=disc>
 <li class=MsoNormal style='mso-list:l1 level1 lfo5;tab-stops:list 36.0pt'><i
     style='mso-bidi-font-style:normal'><span style='font-family:宋体;mso-ascii-font-family:
     "Times New Roman";mso-hansi-font-family:"Times New Roman"'>传递一个越界的索引:</span></i><span
     style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
     "Times New Roman"'>例如,访问某容器的第</span><span lang=EN-US>113</span><span
     style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
     "Times New Roman"'>个元素,而该容器只有</span><span lang=EN-US>100</span><span
     style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
     "Times New Roman"'>个元素。</span></li>
</ul>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<ul style='margin-top:0cm' type=disc>
 <li class=MsoNormal style='mso-list:l1 level1 lfo5;tab-stops:list 36.0pt'><i
     style='mso-bidi-font-style:normal'><span style='font-family:宋体;mso-ascii-font-family:
     "Times New Roman";mso-hansi-font-family:"Times New Roman"'>使用一个并非真正“范围”的迭代器范围:</span></i><span
     style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
     "Times New Roman"'>传递两个迭代器,其中第一个不在第二个之前,或者它们两个并不指向同一个容器。</span></li>
</ul>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<ul style='margin-top:0cm' type=disc>
 <li class=MsoNormal style='mso-list:l1 level1 lfo5;tab-stops:list 36.0pt'><i
     style='mso-bidi-font-style:normal'><span style='font-family:宋体;mso-ascii-font-family:
     "Times New Roman";mso-hansi-font-family:"Times New Roman"'>传递一个无效的迭代器位置:</span></i><span
     style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
     "Times New Roman"'>调用容器的一个以迭代器位置为参数的成员函数,比如传给</span><span lang=EN-US>insert</span><span
     style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
     "Times New Roman"'>的位置,但是传递的迭代器却指向一个不同的容器。</span></li>
</ul>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<ul style='margin-top:0cm' type=disc>
 <li class=MsoNormal style='mso-list:l1 level1 lfo5;tab-stops:list 36.0pt'><i
     style='mso-bidi-font-style:normal'><span style='font-family:宋体;mso-ascii-font-family:
     "Times New Roman";mso-hansi-font-family:"Times New Roman"'>使用无效的顺序:</span></i><span
     style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
     "Times New Roman"'>在给关联型容器排序时,或作为排序算法的比较标准时,提供了无效的排序规则。(示例请参见</span><span
     lang=EN-US> [Meyers01] §21</span><span style='font-family:宋体;mso-ascii-font-family:
     "Times New Roman";mso-hansi-font-family:"Times New Roman"'>。)如果不使用带检查的</span><span
     lang=EN-US>STL</span><span style='font-family:宋体;mso-ascii-font-family:
     "Times New Roman";mso-hansi-font-family:"Times New Roman"'>,一般来说这些都会表现为在运行时的奇怪行为或无限循环,而非不可恢复的错误。</span></li>
</ul>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>通过在容器和迭代器中加入额外的调试和执行信息,大多数带检查的</span><span
lang=EN-US>STL</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>实现会自动地检测出这些错误。例如,迭代器可以记住它指向的容器,容器可以记住所有现存的指向它的迭代器,这样在某些迭代器作废时,容器就可以相应地把它们标记为无效。当然,这使得迭代器变得更大,使得容器要保存额外的状态,使得每次修改容器时都要做额外的工作。但这是值得的——至少在测试的时候,甚至可能在发行的时候(记住第</span><span
lang=EN-US>8</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>条;除非并且直到你知道性能是受其影响而引发的问题,否则不要因为性能的原因而禁用有价值的检查)。</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>即使在发行的时候不打开检查,即使只有一个目标平台有带检查的</span><span
lang=EN-US>STL</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>,最少要确保定期用带检查的</span><span lang=EN-US>STL</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>构建应用程序,并运行完整的测试。今天你这样做,今后你会为此感到高兴的。</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>示例</span></b></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><i style='mso-bidi-font-style:normal'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>示例</span><span lang=EN-US>1</span></i><i style='mso-bidi-font-style:
normal'><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>:使用一个无效的迭代器。</span></i><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>很容易会忘记迭代器是何时作废的并使用一个无效的迭代器(参见第</span><span lang=EN-US>99</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>条)。考虑下面这个改编自</span><span lang=EN-US>[Meyers01]</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>的例子,它把元素插入到一个</span><span lang=EN-US>deque</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>的头部:</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US>deque&lt;double&gt;::iterator
current = d.begin();</span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US>for( size_t i =
0; i &lt; max; ++i )</span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US><span
style='mso-spacerun:yes'>&nbsp; </span>d.insert( current++, data[i] + 41 );<span
style='mso-tab-count:1'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><i
style='mso-bidi-font-style:normal'>// </i></span><i style='mso-bidi-font-style:
normal'><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>你发现错虫了吗?</span></i></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>快:你发现错虫了吗?给你三秒钟。叮!如果你没有在规定时间内发现,不要担心;这是个不太明显的,可以理解的错误。带检查的</span><span
lang=EN-US>STL</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>实现会在循环的第二次迭代时替你检测出这个错误,因此你不必依赖于你无助而敏锐的观察力。(第</span><span
lang=EN-US>84</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>条给出了该代码的一个固定版本,以及这个赤裸裸的循环的一个超级替补。)</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><i style='mso-bidi-font-style:normal'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>示例</span><span lang=EN-US>2</span></i><i style='mso-bidi-font-style:
normal'><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>:使用一个并非真正范围的迭代器范围。</span></i><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>一个迭代器范围是一对</span><span lang=EN-US>first</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>和</span><span lang=EN-US>last</span><span style='font-family:
宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>迭代器,分别指向范围中的第一个元素和最后一个元素之后的那个元素。必须能够通过重复递增</span><span
lang=EN-US>first</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>来到达</span><span lang=EN-US>last</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>。通常有两种方式,会导致意外地使用了并非真正范围的迭代器范围:第一种方式是两个迭代器指向同一个容器,但是</span><span
lang=EN-US>first</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>实际上不在</span><span lang=EN-US>second</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>之前:</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal style='text-indent:36.0pt'><span lang=EN-US>for_each(
c.end(), c.begin(), Something );<span style='mso-tab-count:1'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><i
style='mso-bidi-font-style:normal'>// </i></span><i style='mso-bidi-font-style:
normal'><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>并不总是这么明显</span></i></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>在</span><span lang=EN-US>for_each</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>的内部循环的每次迭代中,它会比较</span><span lang=EN-US>first</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>和</span><span lang=EN-US>second</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>迭代器是否相等,只要不相等它就会继续递增</span><span lang=EN-US>first</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>迭代器。当然,无论把</span><span lang=EN-US>first</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>迭代器递增多少次,它都绝对不会等于</span><span lang=EN-US>second</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>,因此这本质上是个无限循环。在实践中,能遇到的最好的情况是由于越界访问容器</span><span
lang=EN-US>c</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>而引起内存保护错并立即崩溃。最糟糕的情况是越界访问了未知的内存,同时可能还读取或改变了并不属于容器的值。和我们臭名昭著并且非常容易受到攻击的缓冲区溢出相比,这在本质上没有多大的区别。</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>第二种方式是由于使用了指向不同容器的迭代器:</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal style='text-indent:36.0pt'><span lang=EN-US>for_each(
c.begin(), d.end(), Something ); <span style='mso-tab-count:1'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><i
style='mso-bidi-font-style:normal'>// </i></span><i style='mso-bidi-font-style:
normal'><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>并不总是这么明显</span></i></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>结果和前面类似。因为带检查的</span><span lang=EN-US>STL</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>迭代器会记住它指向的容器,所以能够检测到此类运行时的错误。</span></p>

</div>

</body>

</html>

⌨️ 快捷键说明

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