Source

PensarEnC++ / V2-C02.xml

The branch 'PensarEnC++' does not exist.
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
<?xml  version="1.0" encoding="utf-8"?>
<!-- -*- sgml -*- -->
<!--
  Editor:              Emacs 21/PSGML
  Traduccin original:
  Formateado DocBook:
  Revisión:            David Villa Alises
-->

<!-- original en:
http://arco.esi.uclm.es/~david.villa/pensar_en_C++/TICv2/html/TicV2.html#_Toc53985643
-->

<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
                 "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">

<chapter
  xmlns:xi="http://www.w3.org/2001/XInclude"
  id="C02">


  <!-- 2: Defensive Programming -->
  <title>Programación defensiva</title>

  <!--
      Writing “perfect software” may be an elusive Holy Grail for developers, but a few
      defensive techniques, routinely applied, can go a long way toward narrowing the gap
      between code and ideal.
  -->
  <highlights>
    <para>
      Escribir <quote>código perfecto</quote> puede ser un Santo Grial para los
      desarrolladores, pero con unas pocas técnicas defensivas, aplicadas con asiduidad,
      pueden llevar por un largo camino para reducir la distancia entre el código y lo
      ideal.
    </para>
  </highlights>

  <!-- Although the complexity of typical production software
  guarantees that testers will always have a job, we hope you still
  yearn to produce defect-free software. Object-oriented design
  techniques do much to corral the difficulty of large projects, but
  eventually you must write loops and functions. These details of
  programming in the small become the building blocks of the larger
  components needed for your designs. If your loops are off by one or
  your functions calculate the correct values only most of the time,
  you re in trouble no matter how fancy your overall methodology. In
  this chapter, you ll see practices that help create robust code
  regardless of the size of your project. -->
  <para>
    Aunque la complejidad de la producción típica de software garantiza que los probadores
    tendrán siempre trabajo, esperamos que anheles producir software sin defectos. Las
    técnicas de diseño orientado a objetos hacen mucho para limitar la dificultad de crear
    proyectos grandes, pero en último término hay que escribir bucles y funciones. Estos
    pequeños detalles de programación se convierten en los bloques de construcción de
    componentes mayores necesarios para sus diseños. Si sus blucles fallan <quote>por
    uno</quote> o sus funciones calculan los valores correctos sólo la mayoría de las
    veces, tendrá problemas sin importar como de elaborada sea su metodología general. En
    este capítulo, verá prácticas que ayudan a crear código robusto sin importar el tamaño
    de su proyecto.
  </para>

  <!--
       Your code is, among other things, an expression of your attempt to solve a
       problem. It should be clear to the reader (including yourself) exactly what you
       were thinking when you designed that loop. At certain points in your program, you
       should be able to make bold statements that some condition or other holds. (If you
       can't, you really haven't yet solved the problem.) Such statements are called
       invariants, since they should invariably be true at the point where they appear in
       the code; if not, either your design is faulty, or your code does not accurately
       reflect your design. -->


  <para>
    Su código es, entre otras cosas, una expresión de su intento de resolver un
    problema. Debería quedar claro para el lector (incluido usted) que estaba pensando
    exactamente cuando diseño aquel bucle. En ciertos puntos de su programa, debería
    atreverse con sentencias que considera alguna u otra condición. (Si no puede, todavía
    no ha solucionado realmente el problema). Tales sentencias se llaman invariantes,
    puesto que deberían ser invariablemente verdad en el punto donde aparecen en el
    código; si no, o su diseño es defectuoso, o su código no refleja con precisión su
    diseño.
  </para>

  <!--
  Consider a program that plays the guessing game of Hi-Lo. One person
  thinks of a number between 1 and 100, and the other person guesses the
  number. (We'll let the computer do the guessing.) The person who
  holds the number tells the guesser whether their guess is high, low or
  correct. The best strategy for the guesser is a binary search, which
  chooses the midpoint of the range of numbers where the sought-after
  number resides. The high-low response tells the guesser which half of
  the list holds the number, and the process repeats, halving the size
  of the active search range on each iteration. So how do you write a
  loop to drive the repetition properly? It's not sufficient to just
  say
  -->
  <para>
     Considere un programa que juega al juego de adivinar un número diciendo
     mayor-menor. Una persona piensa un número entre el 1 y 100,y la otra persona adivina
     el número. (Podrá al ordenador adivinarlo). La persona que piensa el número le dice
     al adivinador si su conjetura es mayor, menor o correcta. La mejor estrategia para el
     adivinador es la búsqueda binaria, que elige el punto medio del rango de los números
     donde el número buscado reside. La respuesta mayor-menor dice al adivinador que mitad
     de la lista ocupa el número, y el proceso se repite, reduciendo el tamaño del rango
     de búsqueda activo en cada iteración. ¿Entonces cómo escribeiría un bucle para
     realizar la repetición correctamente?  No es suficiente con decir:
  </para>

  <!-- bool guessed = false; -->
  <programlisting>
bool guessed = false;
while(!guessed) {
  ...
}
  </programlisting>

  <!--
  because a malicious user might respond deceitfully, and you could
  spend all day guessing. What assumption, however simple, are you
  making each time you guess? In other words, what condition should hold
  by design on each loop iteration?
  -->
  <para>
    porque un usuario malintencionado podría responder engañosamente,
    y podría pasarse todo el día adivinando. ¿Qué suposición, que sea
    sencilla, está haciendo cada vez que adivina? En otras palabras,
    ¿qué condición debería cumplir por diseño en cada iteración del bucle?
  </para>

  <!--
  The simple assumption is that the secret number is within the current
  active range of unguessed numbers: [1, 100]. Suppose we label the
  endpoints of the range with the variables low and high. Each time you
  pass through the loop you need to make sure that if the number was in
  the range [low, high] at the beginning of the loop, you calculate the
  new range so that it still contains the number at the end of the
  current loop iteration.
  -->
  <para>
    La suposición sencilla es que el número secreto está dentro del
    actual rango activo de números sin adivinar: [1, 100]. Suponga que
    etiquetamos los puntos finales del rango con las variables bajo y
    alto. Cada vez que pasa por el bucle necesita asegurarse que el
    número está en el rango [bajo, alto] al principio del bucle,
    calcule el nuevo rango de modo que todavía contenga el número al
    final de la iteración actual.
  </para>

  <!--
  The goal is to express the loop invariant in code so that a violation
  can be detected at runtime. Unfortunately, since the computer doesn't
  know the secret number, you can't express this condition directly in
  code, but you can at least make a comment to that effect:
  -->
  <para>
    El objetivo es expresar el invariante del bucle en código de modo
    que una violación pueda ser detectada en tiempo de
    ejecución. Desafortunadamente, ya que el ordenador no conoce el
    número secreto, no puede expresar esta condición directamente en
    código, pero puede al menos hacer un comentario para este efecto:
  </para>

<programlisting>
while(!guessed) {
  // INVARIANTE: el número está en el rango [low, high]
  ...
}
</programlisting>

  <!--
  What happens when the user says that a guess is too high or too low
  when it isn't? The deception will exclude the secret number from the
  new subrange. Because one lie always leads to another, eventually your
  range will diminish to nothing (since you shrink it by half each time
  and the secret number isn't in there). We can express this condition
  in the following program:
  -->
  <para>
    ¿Qué ocurre cuando el usuario dice que una conjetura es demasiado
    alta o demasiado baja cuando no lo es? El engaño excluiría el
    número secreto del nuevo subrango. Porque una mentira siempre
    dirige a otra, finalmente su rango disminuirá a nada (puesto que se
    reduce a la mitad cada vez y el número secreto no está
    allí). Podemos expresar esta condición en el siguiente programa:
  </para>


//: V2C02:HiLo.cpp {RunByHand}


  <!--
  The violation of the invariant is detected with the condition if(low >
  high), because if the user always tells the truth, we will always find
  the secret number before we run out of guesses.
  -->
  <para>
    La violación del invariante se detecta con la condición <code>if (menor >
    mayor)</code>, porque si el usuario siempre dice la verdad, siempre encontraremos el
    número secreto antes que agotar los intentos.
  </para>

  <!--
  We also use a standard C technique for reporting program status to the
  calling context by returning different values from main( ). It is
  portable to use the statement return 0; to indicate success, but there
  is no portable value to indicate failure. For this reason we use the
  macro declared for this purpose in <cstdlib>: EXIT_FAILURE. For
  consistency, whenever we use EXIT_FAILURE we also use EXIT_SUCCESS,
  even though the latter is always defined as zero.
  -->
  <para>
    Usamos también una técnica del estándar C para informar sobre el
    estado de un programa al contexto llamante devolviendo diferentes
    valores desde main( ). Es portable para usar la sentencia return
    0; para indicar éxito, pero no hay un valor portable para indicar
    fracaso. Por esta razón usamos la macro declarada para este
    propósito en &lt;cstdlib>:EXIT_FAILURE. Por consistencia, cuando
    usamos EXIT_FAILURE también usamos EXIT_SUCCESS, a pesar de que
    éste está siempre definido como cero.
  </para>

  <sect1>
    <!-- : Assertions -->
    <title>Aserciones </title>

    <!--
    The condition in the Hi-Lo program depends on user input, so you can'
    t prevent a violation of the invariant. However, invariants usually
    depend only on the code you write, so they will always hold if you've
    implemented your design correctly. In this case, it is clearer to make
    an assertion, which is a positive statement that reveals your design
    decisions.
    -->
    <para>
      La condición en el programa mayor-menor depende de la entrada
      del usuario, por lo tanto no puede prevenir una violación del
      invariante. Sin embargo, los invariantes normalmente dependen
      solo del código que escribe, por eso comprobarán siempre si ha
      implementado su diseño correctamente. En este caso, es más claro
      hacer una aserción, que es un sentencia positiva que muestra sus
      decisiones de diseño.
    </para>

    <!--
    Suppose you are implementing a vector of integers: an expandable array
    that grows on demand. The function that adds an element to the vector
    must first verify that there is an open slot in the underlying array
    that holds the elements; otherwise, it needs to request more heap
    space and copy the existing elements to the new space before adding
    the new element (and deleting the old array). Such a function might
    look like the following:
    -->
    <para>
      Suponga que está implementando un vector de enteros: un array
      expandible que crece a petición. La función que añade un
      elemento al vector debe primero verificar que hay un espacio
      vacío en el array subyacente que contiene los elementos; de lo
      contrario, necesita solicitar más espacio en la pila y copiar
      los elementos existentes al nuevo espacio antes de añadir el
      nuevo elemento (y borrar el viejo array). Tal función podría ser
      de la siguiente forma:
    </para>



<programlisting>
void MyVector::push_back(int x) {
if(nextSlot == capacity)
grow();
assert(nextSlot &lt; capacity);
data[nextSlot++] = x;
}
</programlisting>

    <!--
    In this example, data is a dynamic array of ints with capacity slots
    and nextSlot slots in use. The purpose of grow( ) is to expand the
    size of data so that the new value of capacity is strictly greater
    than nextSlot. Proper behavior of MyVector depends on this design
    decision, and it will never fail if the rest of the supporting code is
    correct. We assert the condition with the assert( ) macro, which is
    defined in the header <cassert>.
    -->
    <para>
      En este ejemplo, la información es un array dinámico de ints con
      capacidad espacios y espacioSiguiente espacios en uso. El
      propósito de grow( ) es expandir el tamaño de la información
      para que el nuevo valor de capacidad sea estrictamente mayor
      que espacioSiguiente. El comportamiento correcto de MiVector
      depende de esta decisión de diseño, y nunca fallará si el resto
      del código secundario es correcto. Afirmamos la condición con la
      macro assert( ), que está definido en la cabecera &lt;cassert>.
    </para>

    <!--
    The Standard C library assert( ) macro is brief, to the point, and
    portable. If the condition in its parameter evaluates to non-zero,
    execution continues uninterrupted; if it doesn't, a message
    containing the text of the offending expression along with its source
    file name and line number is printed to the standard error channel and
    the program aborts. Is that too drastic? In practice, it is much more
    drastic to let execution continue when a basic design assumption has
    failed. Your program needs to be fixed.
    -->
    <para>
      La macro assert( ) de la biblioteca Estándar de C es breve, que
      resulta, portable. Si la condición en su parámetro no evalúa a
      cero, la ejecución continúa ininterrumpidamente; si no, un
      mensaje contiene el texto de la expresión culpable con su nombre
      de fichero fuente y el número de línea impreso en el canal de
      error estándar y el programa se suspende. ¿Es eso tan drástico?
      En la práctica, es mucho más drástico permitir que la ejecución
      continue cuando un supuesto de diseño básico ha fracasado. Su
      programa necesita ser arreglado.
    </para>

    <!--
    If all goes well, you will thoroughly test your code with all
    assertions intact by the time the final product is deployed. (We'll
    say more about testing later.) Depending on the nature of your
    application, the machine cycles needed to test all assertions at
    runtime might be too much of a performance hit in the field. If that'
    s the case, you can remove all the assertion code automatically by
    defining the macro NDEBUG and rebuilding the application.
    -->
    <para>
      Si todo va bien, probará a conciencia su código con todas las
      aserciones intactas hasta el momento en que se haga uso del
      producto final. (Diremos más sobre pruebas más tarde.) Depende
      de la naturaleza de su aplicación, los ciclos de máquina
      necesarios para probar todas las aserciones en tiempo de
      ejecución podrían tener demasiado impacto en el rendimiento en
      producción. En ese caso, puede eliminar todas las aserciones del
      código automáticamente definiendo la macro NDEBUG y reconstruir
      la aplicación.
    </para>

    <!--
    To see how this works, note that a typical implementation of assert( )
    looks something like this:
    -->
    <para>
      Para ver como funciona esto, observe que una implementación
      típica de assert( ) se parece a esto:
    </para>

<programlisting>
#ifdef NDEBUG
#define assert(cond) ((void)0)
#else
void assertImpl(const char*, const char*, long);
#define assert(cond) \
((cond) ? (void)0 : assertImpl(???))
#endif
</programlisting>

    <!--
    When the macro NDEBUG is defined, the code decays to the expression
    (void) 0, so all that's left in the compilation stream is an
    essentially empty statement as a result of the semicolon you appended
    to each assert( ) invocation. If NDEBUG is not defined, assert(cond)
    expands to a conditional statement that, when cond is zero, calls a
    compiler-dependent function (which we named assertImpl( )) with a
    string argument representing the text of cond, along with the file
    name and line number where the assertion appeared. (We used as
    a place holder in the example, but the string mentioned is actually
    computed there, along with the file name and the line number where the
    macro occurs in that file. How these values are obtained is immaterial
    to our discussion.) If you want to turn assertions on and off at
    different points in your program, you must not only #define or #undef
    NDEBUG, but you must also re-include <cassert>. Macros are evaluated
    as the preprocessor encounters them and thus use whatever NDEBUG state
    applies at the point of inclusion. The most common way to define
    NDEBUG once for an entire program is as a compiler option, whether
    through project settings in your visual environment or via the command
    line, as in:
    -->
    <para>
      Cuando la macro NDEBUG está definida, el código se descompone a la
      expresión (void) 0, todo lo que queda en la cadena de
      compilación es una sentencia esencialmente vacía como un
      resultado de la semicolumna que añade a cada invocación de
      assert( ). Si NDEBUG no está definido, assert(cond) se expande a
      una sentencia condicional que, cuando cond es cero, llama a una
      función dependiente del compilador (que llamamos assertImpl( ))
      con argumento string representando el texto de cond, junto con
      el nombre de fichero y el número de línea donde aparece la
      aserción. (Usamos como un marcador de posición en el ejemplo,
      pero la cadena mencionada es de hecho computada allí, junto con
      el nombre del fichero y el número de línea donde la macro
      aparece en ese fichero. Como estos valores se obtienen es
      irrelevante para nuestra discusión.) Si quiere activar y
      desactivar aserciones en diferentes puntos de su programa, no
      debe solo #define o #undef NDEBUG, sino que debe también reincluir
      &lt;cassert>. Las macros son evaluadas cuando el preprocesador los
      encuentra y así usa cualquier estado NDEBUG se aplica en el punto
      de inclusión. El camino más común define NDEBUG una vez para
      todo el programa es como una opción del compilador, o mediante
      la configuración del proyecto en su entorno visual o mediante la
      línea de comandos, como en:
    </para>

<screen>
mycc NDEBUG myfile.cpp
</screen>

    <!--
    Most compilers use the flag to define macro names. (Substitute the
    name of your compiler's executable for mycc above.) The advantage of
    this approach is that you can leave your assertions in the source code
    as an invaluable bit of documentation, and yet there is no runtime
    penalty. Because the code in an assertion disappears when NDEBUG is
    defined, it is important that you never do work in an assertion. Only
    test conditions that do not change the state of your program.
    -->
    <para>
      La mayoría de los compiladores usan la bandera para definir los
      nombres de las macros. (Substituya el nombre del ejecutable de su
      compiladores por mycc arriba.) La ventaja de este enfoque es que
      puede dejar sus aserciones en el código fuente como un
      inapreciable parte de documentación, y no hay aún castigo en
      tiempo de ejecución. Porque el código en una aserción desaparece
      cuando NDEBUG está definido, es importante que no haga trabajo
      en una aserción. Sólo las condiciones de prueba que no cambien
      el estado de su programa.
    </para>

    <!--
    Whether using NDEBUG for released code is a good idea remains a
    subject of debate. Tony Hoare, one of the most influential computer
    scientists of all time,[15] has suggested that turning off runtime
    checks such as assertions is similar to a sailing enthusiast who wears
    a life jacket while training on land and then discards it when he goes
    to sea.[16] If an assertion fails in production, you have a problem
    much worse than degradation in performance, so choose wisely.
    -->
    <para>
      Si usar NDEBUG para liberar código es una buena idea queda un
      tema de debate. Tony Hoare, una de los más influyentes expertos
      en informática de todos los tiempos,[15] ha sugerido que
      desactivando las comprobaciones en tiempo de ejecución como las
      aserciones es similar a un entusiasta de navegación que lleva un
      chaleco salvavidas mientras entrena en tierra y luego se deshace
      de él cuando va al mar.[16] Si una aserción falla en producción,
      tiene un problema mucho peor que la degradación en rendimiento,
      así que elija sabiamente.
    </para>

    <!--
    Not all conditions should be enforced by assertions. User errors and
    runtime resource failures should be signaled by throwing exceptions,
    as we explained in detail in Chapter 1. It is tempting to use
    assertions for most error conditions while roughing out code, with the
    intent to replace many of them later with robust exception
    handling. Like any other temptation, use caution, since you might
    forget to make all the necessary changes later. Remember: assertions
    are intended to verify design decisions that will only fail because of
    faulty programmer logic. The ideal is to solve all assertion
    violations during development. Don't use assertions for conditions
    that aren't totally in your control (for example, conditions that
    depend on user input). In particular, you wouldn't want to use
    assertions to validate function arguments; throw a logic_error
    instead.
    -->
    <para>
      No todas las condiciones deberían ser cumplidas por
      aserciones. Los errores de usuario y los fallos de los
      recursos en tiempos de ejecución deberían ser señalados lanzando
      excepciones, como explicamos en detalle en el Capítulo 1. Es
      tentador usar aserciones para la mayoría de las condiciones de
      error mientras esbozamos código, con el propósito de remplazar
      muchos de ellos después con un manejador de excepciones
      robusto. Como cualquier otra tentación, úsese con moderación, pues
      podría olvidar hacer todos los cambios necesarios más
      tarde. Recuerde: las aserciones tienen la intención de verificar
      decisiones de diseño que fallarán sólo por lógica
      defectuosa del programador. Lo ideal es solucionar todas las
      violaciones de aserciones durante el desarrollo. No use
      aserciones para condiciones que no están totalmente en su
      control (por ejemplo, condiciones que dependen de la entrada del
      usuario). En particular, no querría usar aserciones para validar
      argumentos de función; lance un logic_error en su lugar.
    </para>

    <!--
    The use of assertions as a tool to ensure program correctness was
    formalized by Bertrand Meyer in his Design by Contract
    methodology.[17] Every function has an implicit contract with clients
    that, given certain preconditions, guarantees certain
    postconditions. In other words, the preconditions are the requirements
    for using the function, such as supplying arguments within certain
    ranges, and the postconditions are the results delivered by the
    function, either by return value or by side-effect.
    -->
    <para>
      El uso de aserciones como una herramienta para asegurar la
      corrección de un programa fue formalizada por Bertran Meyer en
      su Diseño mediante metodología de contrato.[17] Cada función
      tiene un contrato implícito con los clientes que, dadas ciertas
      precondiciones, garantiza ciertas postcondiciones. En otras
      palabras, las precondiciones son los requerimientos para usar la
      función, como los argumentos que se facilitan dentro de ciertos
      rangos, y las postcondiciones son los resultados enviados por la
      función o por retorno por valor o por efecto colateral.
    </para>

    <!--
    When client programs fail to give you valid input, you must tell them
    they have broken the contract. This is not the best time to abort the
    program (although you're justified in doing so since the contract was
    violated), but an exception is certainly appropriate. This is why the
    Standard C++ library throws exceptions derived from logic_error, such
    as out_of_range.[18] If there are functions that only you call,
    however, such as private functions in a class of your own design, the
    assert( ) macro is appropriate, since you have total control over the
    situation and you certainly want to debug your code before shipping.
    -->
    <para>
      Cuando los programas clientes fallan al darle un entrada válida,
      debe comentarles que han roto el contrato. Este no es el mejor
      momento para suspender el programa (aunque está justificado
      hacerlo desde que el contrato fue violado), pero una excepción
      es desde luego apropiada. Esto es porque la librería Estándar de
      C++ lanza excepciones derivadas de logic_error, como
      out_of_range.[18] Si hay funciones que sólo usted llama, no
      obstante, como funciones privadas en una clase de su propio
      diseño, la macro assert( ) es apropiada, puesto que tiene total
      control sobre la situación y desde luego quiere depurar su
      código antes de enviarlo.
    </para>

    <!--
    A postcondition failure indicates a program error, and it is
    appropriate to use assertions for any invariant at any time, including
    the postcondition test at the end of a function. This applies in
    particular to class member functions that maintain the state of an
    object. In the MyVector example earlier, for instance, a reasonable
    invariant for all public member functions would be:
    -->
    <para>
      Una postcondición fallada indica un error de programa, y es
      apropiado usar aserciones para cualquier invariante en cualquier
      momento, incluyendo la postcondición de prueba al final de una
      función. Esto se aplica en particular a las funciones de una
      clase que mantienen el estado de un objeto. En el ejemplo
      MyVector previo, por ejemplo, un invariante razonable para todas
      las funciones sería:
    </para>

    <!-- assert(0 &lt;= nextSlot &amp;&amp; nextSlot &lt;= capacity); -->
    <para>
      assert(0 &lt;= siguienteEspacio &amp;&amp; siguienteEspacio &lt;= capacidad);
    </para>

    <!-- or, if nextSlot is an unsigned integer, simply -->
    <para>
      o, si siguienteEspacio es un integer sin signo, sencillamente
    </para>

    <!-- assert(nextSlot &lt;= capacity); -->
    <para>
      assert(siguienteEspacio &lt;= capacidad);
    </para>

    <!--
    Such an invariant is called a class invariant and can reasonably be
    enforced by an assertion. Subclasses play the role of subcontractor to
    their base classes because they must maintain the original contract
    between the base class and its clients. For this reason, the
    preconditions in derived classes must impose no extra requirements
    beyond those in the base contract, and the postconditions must deliver
    at least as much.[19]
    -->
    <para>
      Tal tipo de invariante se llama invariante de clase y puede ser
      razonablemente forzada por una aserción. Las subclases juegan un
      papel de subcontratista para sus clases base porque deben
      mantener el contrato original entre la clase base y sus
      clientes. Por esta razón, las precondiciones en clases derivadas
      no deben imponer requerimientos adicionales más allá de aquellos
      del contrato base, y las postcondiciones deben cumplir al menos como
      mucho.[19]
    </para>

    <!--
    Validating results returned to the client, however, is nothing more or
    less than testing, so using post-condition assertions in this case
    would be duplicating work. Yes, it's good documentation, but more
    than one developer has been fooled into improperly using
    post-condition assertions as a substitute for unit testing.
    -->
    <para>
      Validar resultados devueltos por el cliente, sin embargo, no es
      más o menos que probar, de manera que usar aserciones de postcondición
      en este caso sería duplicar trabajo. Sí, es buena documentación,
      pero más de un desarrollador has sido engañado usando
      incorrectamente las aserciones de post-condición como un
      substituto para pruebas de unidad.
    </para>

  </sect1>
  <sect1>
    <!-- : A simple unit test framework -->
    <title>Un framework de pruebas unitarias sencillo </title>

    <!--
    Writing software is all about meeting requirements.[20] Creating these
    requirements is difficult, and they can change from day to day; you
    might discover at a weekly project meeting that what you just spent
    the week doing is not exactly what the users really want.
    -->
    <para>
      Escribir software es todo sobre encontrar requerimientos.[20]
      Crear estos requerimientos es difícil, y pueden cambiar de un
      día a otro; podría descubrir en una reunión de proyecto semanal
      que lo que ha empleado la semana haciendo no es exactamente lo
      que los usuarios realmente quieren.
    </para>

    <!--
    People cannot articulate software requirements without sampling an
    evolving, working system. It's much better to specify a little,
    design a little, code a little, and test a little. Then, after
    evaluating the outcome, do it all over again. The ability to develop
    in such an iterative fashion is one of the great advances of the
    object-oriented approach, but it requires nimble programmers who can
    craft resilient code. Change is hard.
    -->
    <para>
      Las personas no pueden articular requerimientos de software sin
      muestrear un sistema de trabajo en evolución. Es mucho mejor
      especificar un poco, diseñar un poco, codificar un poco y probar
      un poco. Entonces, después de evaluar el resultado, hacerlo todo
      de nuevo. La habilidad para desarrollar con una moda iterativa
      es uno de los mejores avances del enfoque orientado a objetos,
      pero requiere programadores ágiles que pueden hacer código
      fuerte. El cambio es duro.
    </para>

    <!--
    Another impetus for change comes from you, the programmer. The
    craftsperson in you wants to continually improve the design of your
    code. What maintenance programmer hasn't cursed the aging, flagship
    company product as a convoluted, unmodifiable patchwork of spaghetti?
    Management's reluctance to let you tamper with a functioning system
    robs code of the resilience it needs to endure. If it's not broken,
    don't fix it eventually gives way to, We can't fix it rewrite
    it. Change is necessary.
    -->
    <para>
      Otro ímpetu para el cambio viene de usted, el programador. El
      artífice que hay en usted quiere continuamente mejorar el diseño
      de su código. ¿Qué programador de mantenimiento no ha maldecido
      el envejecimiento, el producto de la compañía insignia como un
      mosaico de espaguetis inmodificable, enrevesado? La reluctancia
      de los supervisores en permitir que uno interfiera con un
      sistema que funciona le roba al código la
      flexibilidad que necesita para que perdure. Si no
      está roto, no arreglarlo finalmente le da el camino para, no
      podemos arreglarlo reescribámoslo. El cambio es necesario.
    </para>

    <!--
    Fortunately, our industry is growing accustomed to the discipline of
    refactoring, the art of internally restructuring code to improve its
    design, without changing its behavior.[21] Such improvements include
    extracting a new function from another, or inversely, combining member
    functions; replacing a member function with an object; parameterizing
    a member function or class; and replacing conditionals with
    polymorphism. Refactoring helps code evolve.
    -->
    <para>
      Afortunadamente, nuestra industria está creciendo acostumbrada
      a la disciplina de refactoring, el arte de reestructura
      internamente código para mejorar su diseño, sin cambiar su
      comportamiento.[21] Tales mejoras incluyen extraer una nueva
      función de otra, o de forma inversa, combinar funciones,
      reemplazar una función con un objeto; parametrizar una función o
      clase; y reemplazar condicionales con polimorfismo. Refactorizar
      ayuda al código evolucionar.
    </para>

    <!--
    Whether the force for change comes from users or programmers, changes
    today may break what worked yesterday. We need a way to build code
    that withstands change and improves over time.
    -->
    <para>
      Si la fuerza para el cambio viene de los usuarios o
      programadores, los cambios hoy pueden destrozar lo trabajado
      ayer. Necesitamos un modo para construir código que resista el
      cambio y mejoras a lo largo del tiempo.
    </para>

    <!--
    Extreme Programming (XP)[22] is only one of many practices that
    support a quick-on-your-feet motif. In this section we explore what we
    think is the key to making flexible, incremental development succeed:
    an easy-to-use automated unit test framework. (Note that testers,
    software professionals who test others' code for a living, are still
    indispensable. Here, we are merely describing a way to help developers
    write better code.)
    -->
    <para>
      La Programación Extrema (XP)[22] es sólo uno de las muchas
      prácticas que motivan la agilidad. En esta
      sección exploramos lo que pensamos es la clave para hacer un
      desarrollo flexible, incremental que tenga éxito: un framework
      de pruebas unitarias automatizada fácil de usar. (Note que los
      probadores, profesionales de software que prueban el código de
      otros para ganarse la vida, son todavía indispensables. Aquí,
      estamos simplemente describiendo un modo para ayudar a los
      desarrolladores a escribir mejor código.)
    </para>

    <!--
    Developers write unit tests to gain the confidence to say the two most
    important things that any developer can say:
    -->
    <para>
      Los desarrolladores escriben pruebas unitarias para conseguir
      confianza para decir las dos cosas más importantes que
      cualquier desarrollador puede decir:
    </para>

    <!-- 1.      I understand the requirements. -->
    <para>
      1. Entiendo los requerimientos.
    </para>

    <!-- 2.      My code meets those requirements (to the best of my knowledge). -->
    <para>
      Mi código cumple esos requerimientos (hasta donde yo sé)
    </para>

    <!--
    There is no better way to ensure that you know what the code you're
    about to write should do than to write the unit tests first. This
    simple exercise helps focus the mind on the task ahead and will likely
    lead to working code faster than just jumping into coding. Or, to
    express it in XP terms:
    -->
    <para>
      No hay mejor modo para asegurar que sabe lo que el código que está por
      escribir debería hacer mejor que escribir primero pruebas
      unitarias. Este ejercicio sencillo ayuda a centrar la mente en las
      tareas siguientes y probablemente guiará a código que
      funcionalmente más rápido mejor que sólo saltar a codificar. O,
      expresarlo en términos XP:
    </para>

    <!-- Testing + programming is faster than just programming. -->
    <para>
      Probar + programar es más rápido que sólo programar.
    </para>

    <!--
    Writing tests first also guards you against boundary conditions that
    might break your code, so your code is more robust.
    -->
    <para>
      Escribir primero pruebas sólo le protegen contra condiciones
      límite que podrían destrozar su código, por lo tanto su código
      es más robusto.
    </para>

    <!-- When your code passes all your tests, you know that if the
    system isn't working, your code is probably not the problem. The
    statement All my tests pass is a powerful argument. -->
    <para>
      Cuando su código pasa todas sus pruebas, sabe que si el sistema no
      está funcionando, su código no es probablemente el problema. La
      frase todas mis pruebas funcionan es un fuerte razonamiento.
    </para>

    <sect2>
      <!-- : Automated testing -->
      <title> Pruebas automatizadas </title>


      <!--
      So what does a unit test look like? Too often developers just use some
      well-behaved input to produce some expected output, which they inspect
      visually. Two dangers exist in this approach. First, programs don't
      always receive only well-behaved input. We all know that we should
      test the boundaries of program input, but it's hard to think about
      this when you're trying to just get things working. If you write the
      test for a function first before you start coding, you can wear your
      tester hat and ask yourself, What could possibly make this
      break? Code a test that will prove the function you'll write isn't
      broken, and then put on your developer hat and make it happen. You'll
      write better code than if you hadn't written the test first.
      -->
      <para>
	Por lo tanto, ¿qué aspecto tiene una prueba unitaria? Demasiado
	a menudo los desarrolladores simplemente usan alguna entrada
	correcta para producir alguna salida esperada, que examinan
	visualmente. Existen dos peligros en este enfoque. Primero,
	los programas no siempre reciben sólo entradas
	correctas. Todos sabemos que deberíamos probar los límites de
	entrada de un programa, pero es duro pensar esto cuando está
	intentando simplemente hacer que las cosas funcionar. Si escribe
	primero la prueba para una función antes de comenzar a
	codificar, puede ponerse su traje de probador y preguntarse a
	si mismo, ¿qué haría posiblemente destrozar esto? Codificar
	una prueba que probará la función que escribirá no es erróneo,
	y luego ponerte el traje de desarrollador y hacerlo
	pasar. Escribirá mejor código que si no había escrito la
	prueba primero.
      </para>

      <!--
      The second danger is that inspecting output visually is tedious and
      error prone. Most any such thing a human can do a computer can do, but
      without human error. It's better to formulate tests as collections of
      Boolean expressions and have a test program report any failures.
      -->
      <para>
	El segundo peligro es que esperar una salida visualmente es
	tedioso y propenso a error. La mayoría de cualquier tipo de cosas que un
	humano puede hacer un ordenador puede hacerlas, pero sin el
	error humano. Es mejor formular pruebas como colecciones
	de expresiones boolean y tener un programa de prueba que
	informa de cualquier fallo.
      </para>

      <!--
      For example, suppose you need to build a Date class that has the
      following properties:
      -->
      <para>
	Por ejemplo, suponga que necesita construir una clase Fecha
	que tiene las siguientes propiedades:
      </para>

      <!-- A date can be initialized with a string (YYYYMMDD), three
      integers (Y, M, D), or nothing (giving today's date). -->
      <para>
	Una fecha puede estar inicializada con una cadena (AAAAMMDD),
	3 enteros (A, M, D), o nada (dando la fecha de hoy).
      </para>

      <!-- A date object can yield its year, month, and day or a
      string of the form YYYYMMDD. -->
      <para>
	Un objecto fecha puede producir su año, mes y día o una cadena
	de la forma AAAAMMDD.
      </para>

      <!-- All relational comparisons are available, as well as
      computing the duration between two dates (in years, months, and
      days). -->
      <para>
	Todas las comparaciones relacionales están disponibles, además
	de calcular la duración entre dos fechas (en años, meses, y
	días).
      </para>

      <!-- Dates to be compared need to be able to span an arbitrary
      number of centuries (for example, 16002200). -->
      <para>
	Las fechas para ser comparadas necesitan poder extenderse un
	número arbitrario de siglos(por ejemplo, 16002200).
      </para>

      <!--
      Your class can store three integers representing the year, month, and
      day. (Just be sure the year is at least 16 bits in size to satisfy the
      last bulleted item.) The interface for your Date class might look like
      this:
      -->
      <para>
	Su clase puede almacenar tres enteros que representan el año, mes
	y día. (Sólo asegúrese que el año es al menos de 16 bits de
	tamaño para satisfacer el último punto.) La interfaz de su
	clase Fecha se podría parecer a esto:
      </para>


//: V2C02:Date1.h


      <!--
      Before you implement this class, you can solidify your grasp of the
      requirements by writing the beginnings of a test program. You might
      come up with something like the following:
      -->
      <para>
	Antes de que implemente esta clase, puede solidificar sus
	conocimientos de los requerimientos escribiendo el principio
	de un programa de prueba. Podría idear algo como lo siguiente:
      </para>



//: V2C02:SimpleDateTest.cpp


      <!--
      In this trivial case, the function test( ) maintains the global
      variables nPass and nFail. The only visual inspection you do is to
      read the final score. If a test failed, a more sophisticated test( )
      displays an appropriate message. The framework described later in this
      chapter has such a test function, among other things.
      -->
      <para>
	En este caso trivial, la función test( ) mantiene las
	variables globales nAprobar y nSuspender. La única revisión
	visual que hace es leer el resultado final. Si una prueba falla,
	un test( ) más sofisticado muestra un mensaje apropiado. El
	framework descrito más tarde en este capítulo tiene un función
	de prueba, entre otras cosas.
      </para>

      <!--
      You can now implement enough of the Date class to get these tests to
      pass, and then you can proceed iteratively until all the requirements
      are met. By writing tests first, you are more likely to think of
      corner cases that might break your upcoming implementation, and you'
      re more likely to write the code correctly the first time. Such an
      exercise might produce the following version of a test for the Date
      class:
      -->
      <para>
	Puede ahora implementar la clase Fecha para hacer pasar estas
	pruebas, y luego puede proceder iterativamente hasta que se
	satisfagan todos los requerimientos. Escribiendo primero
	pruebas, es más probable que piense en casos límite que podrían
	destrozar su próxima implementación, y es más probable que
	escriba el código correctamente la primera vez. Como ejercicio
	podría realizar la siguiente versión de una prueba
	para la clase Fecha:
      </para>


//: V2C02:SimpleDateTest2.cpp

      <!--
      This test can be more fully developed. For example, we haven't tested
      that long durations are handled correctly. We'll stop here, but you
      get the idea. The full implementation for the Date class is available
      in the files Date.h and Date.cpp in the appendix.[23]
      -->
      <para>
	Esta prueba puede ser desarrollada por completo. Por ejemplo,
	no hemos probado que duraciones grandes son manejadas
	correctamente. Pararemos aquí, pero coja la idea. La
	implementación entera para la case Fecha está disponible en
	los ficheros Date.h y Date.cpp en el apéndice.[23]
      </para>

    </sect2>
    <sect2>
      <!-- :  The TestSuite Framework -->
      <title>El Framework TestSuite </title>

      <!--
      Some automated C++ unit test tools are available on the World Wide Web
      for download, such as CppUnit.[24] Our purpose here is not only to
      present a test mechanism that is easy to use, but also easy to
      understand internally and even modify if necessary. So, in the spirit
      of Do The Simplest Thing That Could Possibly Work,[25] we have
      developed the TestSuite Framework, a namespace named TestSuite that
      contains two key classes: Test and Suite.
      -->
      <para>
	Algunas herramientas de pruebas unitarias automatizadas de C++
	están disponibles en la World Wide Web para descargar, como
	CppUnit.[24] Nuestra intención aquí no es sólo presentar un
	mecanismo de prueba que sea fácil de usar, sino también fácil
	de entender internamente e incluso modificar si es
	necesario. Por lo tanto, en el espíritu de Hacer Lo Más Simple
	Que Podría Posiblemente Funcionar,[25] hemos desarrollado el
	Framework TestSuite, un espacio de nombres llamado TestSuite
	que contiene dos clases principales: Test y Suite.
      </para>

      <!--
      The Test class is an abstract base class from which you derive a test
      object. It keeps track of the number of passes and failures and
      displays the text of any test condition that fails. You simply to
      override the run( ) member function, which should in turn call the
      test_( ) macro for each Boolean test condition you define.
      -->
      <para>
	La clase Test es una clase base abstracta de la cual deriva un
	objeto test. Tiene constancia del número de éxitos y
	fracasos y muestra el texto de cualquier condición de prueba
	que falla. Simplemente para sobreescribir la función run( ),
	que debería llamar en turnos a la macro test_() para cada
	condición de prueba boolean que defina.
      </para>


      <!--
      To define a test for the Date class using the framework, you can
      inherit from Test as shown in the following program:
      -->
      <para>
	Para definir una prueba para la clase Fecha usando el
	framework, puede heredar de Test como se muetra en el
	siguiente programa:
      </para>


//: V2C02:DateTest.h


      <!--
      Running the test is a simple matter of instantiating a DateTest object
      and calling its run( ) member function:
      -->
      <para>
	Ejecutar la prueba es una sencilla cuestión de instaciación
	de un objeto DateTest y llamar a su función run( ):
      </para>


//: V2C02:DateTest.cpp


      <!--
      The Test::report( ) function displays the previous output and returns
      the number of failures, so it is suitable to use as a return value
      from main( ).
      -->
      <para>
	La función Test::report( ) muestra la salida previa y devuelve
	el número de fallos, de este modo es conveniente usarlo como
	valor de retorno desde el main( ).
      </para>

      <!--
      The Test class uses RTTI[26] to get the name of your class (for
      example, DateTest) for the report. There is also a setStream( ) member
      function if you want the test results sent to a file instead of to the
      standard output (the default). You'll see the Test class
      implementation later in this chapter.
      -->
      <para>
	La clase Test usa RTTI[26] para obtener el nombre de su
	clase(por ejemplo, DateTest) para el informe. Hay también una
	función setStream() si quiere enviar los resultados de la
	prueba a un fichero en lugar de la salida estándar (por
	defecto). Verá la implementación de la clase Test más tarde en
	este capítulo.
      </para>

      <!--
      The test_( ) macro can extract the text of the Boolean condition that
      fails, along with its file name and line number.[27] To see what
      happens when a failure occurs, you can introduce an intentional error
      in the code, for example by reversing the condition in the first call
      to test_( ) in DateTest::testOps( ) in the previous example code. The
      output indicates exactly what test was in error and where it happened:
      -->
      <para>
	La macro test_( ) puede extraer el texto de la condición
	booleana que falla, junto con el nombre del fichero y número
	de línea.[27] Para ver lo que ocurre cuando un fallo aparece,
	puede insertar un error intencionado en el código, por ejemplo
	invirtiendo la condición en la primera llamda a test_( ) en
	DateTest::testOps( ) en el código de ejemplo previo. La salida
	indica exactamente que la prueba tenía un error y dónde ocurrió:
      </para>

      <!--
      DateTest failure: (mybday > today) , DateTest.h (line 31)
      Test "DateTest":
      Passed: 20      Failed: 1
      -->
      <para>
	DateTest fallo: (mybday > hoy) , DateTest.h (línea 31)
	Test "DateTest":
	Passados: 20  Fallados: 1
      </para>

      <!--
      In addition to test_( ), the framework includes the functions
      succeed_( ) and fail_( ), for cases where a Boolean test won't
      do. These functions apply when the class you're testing might throw
      exceptions. During testing, create an input set that will cause the
      exception to occur. If it doesn't, it's an error and you call fail_(
      ) explicitly to display a message and update the failure count. If it
      does throw the exception as expected, you call succeed_( ) to update
      the success count.
      -->
      <para>
	Además de test_( ), el framework incluye las funciones
	succed_( ) y fail_( ), para casos donde una prueba Boolean no
	funcionará. Estas funciones se aplican cuando la clase que está
	probando podría lanzar excepciones. Durante la prueba, crear
	un conjunto de entrada que causará que la excepción aparezca. Si
	no, es un error y puede llamar a fail_( ) explicitamente para
	mostrar un mensaje y actualizar el contador de fallos. Si
	lanza la excecpión como se esperaba, llame a succeed_( ) para
	actualizar el contador de éxitos.
      </para>

      <!-- To illustrate, suppose we modify the specification of the
      two non-default Date constructors to throw a DateError exception
      (a type nested inside Date and derived from std::logic_error) if
      the input parameters do not represent a valid date: Date(const
      string& s) throw(DateError); Date(int year, int month, int day)
      throw(DateError); -->
      <para>
	Para ilustrar, suponga que modificamos la especificación de
	los dos constructor no por defecto de Date para lanzar una
	excepción DateError (un tipo anidado dentro de Date y derivado
	de std::logic_error) si los parámetros de entrada no representa
	un fecha válida: Date(const string&amp; s) throw(DateError);
	Date(int year, int month, int day) throw(DateError);
      </para>

      <!--
      The DateTest::run( ) member function can now call the following
      function to test the exception handling:
	-->
      <para>
	La función DateTest::run( ) puede ahora llamar a la siguiente
	función para probar el manejo de excepciones:
      </para>

<programlisting>
void testExceptions() {
try {
Date d(0,0,0);  // Invalid
fail_("Invalid date undetected in Date int ctor");
} catch(Date::DateError&amp;) {
succeed_();
}
try {
Date d("");  // Invalid
fail_("Invalid date undetected in Date string ctor");
} catch(Date::DateError&amp;) {
succeed_();
}
}
</programlisting>
      <!--
      In both cases, if an exception is not thrown, it is an error. Notice
      that you must manually pass a message to fail_( ), since no Boolean
      expression is being evaluated.
      -->
      <para>
	En ambos casos, si una excepción no se lanza, es un
	error. Fíjese que debe pasar manualmente un mensaje a
	fail_( ), pues no se está evaluando una expresión booleana.
      </para>

    </sect2>
    <sect2>
      <!-- : Test suites -->
      <title>Suites de test </title>

      <!--
      Real projects usually contain many classes, so you need a way to group
      tests so that you can just push a single button to test the entire
      project.[28] The Suite class collects tests into a functional
      unit. You add Test objects to a Suite with the addTest( ) member
      function, or you can include an entire existing suite with addSuite(
      ). To illustrate, the following example collects the programs in
      Chapter 3 that use the Test class into a single suite. Note that this
      file will appear in the Chapter 3 subdirectory:
      -->
      <para>
	Los proyectos reales contienen normalmente muchas clases, por lo
	tanto necesita un modo para agrupar pruebas para que pueda
	simplemente pulsar un solo botón para probar el proyecto
	entero.[28] La clase Suite recoge pruebas en una unidad
	funcional. Añada objetos Test a Suite con la función addTest(
	), o puede incluir una suite existente entera con addSuite(
	). Para ilustrar, el siguiente ejemplo reúna los programas del
	Capítulo 3 que usa la clase Test en una sola suite. Fíjese
	que este fichero aparecerá en el subdirectorio del Capítulo 3:
      </para>



//: V2C03:StringSuite.cpp


<!-- #REVISAR# -->

      <!--
      Five of the above tests are completely contained in header
      files. TrimTest is not, because it contains static data that must be
      defined in an implementation file. The two first two output lines are
      trace lines from the StringStorage test. You must give the suite a
      name as a constructor argument. The Suite::run( ) member function
      calls Test::run( ) for each of its contained tests. Much the same
      thing happens for Suite::report( ), except that you can send the
      individual test reports to a different destination stream than that of
      the suite report. If the test passed to addSuite( ) already has a
      stream pointer assigned, it keeps it. Otherwise, it gets its stream
      from the Suite object. (As with Test, there is an optional second
      argument to the suite constructor that defaults to std::cout.) The
      destructor for Suite does not automatically delete the contained Test
      pointers because they don't need to reside on the heap; that's the
      job of Suite::free( ).
      -->
      <para>
	5 de los tests de más arriba están completamente contenidos en
	los ficheros de cabecera. TrimTest no lo está, porque contiene
	datos estáticos que deben estar definidos en un fichero de
	implementación. Las dos primeras líneas de salida son trazos
	de la prueba StringStorage. Debe dar a la suite un nombre como
	argumento del constructor. La función Suite::run( ) llama a
	Test::run( ) po cada una de las pruebas que tiene. Más de
	lo mismo pasa con Suite::report( ), excepto que puede enviar
	los informes de pruebas individuales a cadenas destinaciones
	diferentes  mejor que el informe de la suite. Si la prueba pasa
	a addSuite( ) ya tiene un puntero de cadena asignado, que
	lo guarda. En otro caso, obtiene su cadena del objeto
	Suite. (Como con Test, hay un segundo argumento opcional  para
	el constructor suite que no se presenta a std::cout.) El
	destructor para Suite no borra automáticamente los punteros
	contenidos en Test porque no necesitan residir en la pila;
	este es el trabajo de Suite::free( ).
      </para>

    </sect2>
    <sect2>
      <!-- : The test framework code -->
      <title>El código del framework de prueba </title>

      <!--
      The test framework code is in a subdirectory called TestSuite in the
      code distribution available at www.MindView.net. To use it, include
      the search path for the TestSuite subdirectory in your header, link
      the object files, and include the TestSuite subdirectory in the
      library search path. Here is the header for Test.h:
      -->
      <para>
	El código del framework de pruebas es un subdirectorio llamado
	TestSuite en la distribución de código disponible en
	www.MindView.net. Para usarlo, incluya la ruta de búsqueda
	para el subdirectorio TestSuite en la ruta de búsqueda de la
	biblioteca. Aquí está la cabecera para Test.h:
      </para>


<example>
<title></title>
<programlisting language="C++">
<xi:include parse="text" href="./code_v2/TestSuite/Test.h"/>
</programlisting>
</example>


      <!-- There are three virtual functions in the Test class: -->
      <para>
	Hay tres funciones virtuales en la clase Test:
      </para>

      <!-- A virtual destructor -->
      <para>
	Un destructor virtual
      </para>

      <!-- The function reset( ) -->
      <para>
	La función reset( )
      </para>

      <!-- The pure virtual function run( ) -->
      <para>
	La función virtual pura run( )
      </para>

      <!--
      As explained in Volume 1, it is an error to delete a derived heap
      object through a base pointer unless the base class has a virtual
      destructor. Any class intended to be a base class (usually evidenced
      by the presence of at least one other virtual function) should have a
      virtual destructor. The default implementation of the Test::reset( )
      resets the success and failure counters to zero. You might want to
      override this function to reset the state of the data in your derived
      test object; just be sure to call Test::reset( ) explicitly in your
      override so that the counters are reset. The Test::run( ) member
      function is pure virtual since you are required to override it in your
      derived class.
      -->
      <para>
	Como se explicó en el Volumen 1, es un error eliminar un
	objeto derivado de la pila a través de un puntero base a
	menos que la clase base tenga un destructor virtual. Cualquier
	clase propuesta para ser una clase base (normalmente
	evidenciadas por la presencia de al menos una de las otras
	funciones virtuales) tendría un destructor virtual. La
	implementación por defecto de Test::reset( ) pone los
	contadores de éxitos y fallos a cero. Podría querer
	sobreescribir esta función para poner el estado de los datos
	en su objeto de test derivado; sólo asegúrese de llamar a
	Test::rest( ) explícitamente en su sobreescritura de modo que
	los contadores se reajusten. La función Test::run( ) es
	virtual pura ya que es necesario para sobreescribirla en su
	clase derivada.
      </para>

      <!--
      The test_( ) and fail_( ) macros can include file name and line number
      information available from the preprocessor. We originally omitted the
      trailing underscores in the names, but the fail( ) macro then collided
      with ios::fail( ), causing compiler errors.
      -->
      <para>
	Las macros test_( ) y fail_( ) pueden incluir la información
	disponible del nombre del fichero y el número de línea del
	preprocesador. Originalmente omitimos el guión bajo en los
	nombres, pero la macro fail colisiona con ios::fail( ),
	provocando errores de compilación.
      </para>

      <!-- Here is the implementation of the remainder of the Test functions: -->
      <para>
	Aquí está la implementación del resto de las funciones Test:
      </para>


<example>
<title></title>
<programlisting language="C++">
<xi:include parse="text" href="./code_v2/TestSuite/Test.cpp"/>
</programlisting>
</example>


      <!--
      The Test class keeps track of the number of successes and failures as
      well as the stream where you want Test::report( ) to display the
      results. The test_( ) and fail_( ) macros extract the current file
      name and line number information from the preprocessor and pass the
      file name to do_test( ) and the line number to do_fail( ), which do
      the actual work of displaying a message and updating the appropriate
      counter. We can't think of a good reason to allow copy and assignment
      of test objects, so we have disallowed these operations by making
      their prototypes private and omitting their respective function
      bodies.
      -->
      <para>
	La clase Test lleva la cuenta del número de éxitos y fracasos
	además de la cadena donde quiere que Test::report( ) muestre los
	resultados. Las macros test_( ) y fail_() extraen la
	información del nombre del fichero actual y el número de línea
	del preprocesador y pasa el nombre del fichero a do_test( ) y
	el número de línea a do_fail( ), que hacen el mismo trabajo de
	mostrar un mensaje y actualizar el contador apropiado. No
	podemos pensar una buena razón para permitir copiar y asignar
	objetos de prueba, por lo que hemos rechazado estas
	operaciones para hacer sus prototipos privados y omitir el
	cuerpo de sus respectivas funciones.
      </para>

      <!-- Here is the header file for Suite: -->
      <para>
	Aquí está el fichero de cabecera para Suite:
      </para>



<example>
<title></title>
<programlisting language="C++">
<xi:include parse="text" href="./code_v2/TestSuite/Suite.h"/>
</programlisting>
</example>


      <!--
      The Suite class holds pointers to its Test objects in a vector. Notice
      the exception specification on the addTest( ) member function. When
      you add a test to a suite, Suite::addTest( ) verifies that the pointer
      you pass is not null; if it is null, it throws a TestSuiteError
      exception. Since this makes it impossible to add a null pointer to a
      suite, addSuite( ) asserts this condition on each of its tests, as do
      the other functions that traverse the vector of tests (see the
      following implementation). Copy and assignment are disallowed as they
      are in the Test class.
      -->
      <para>
	La clase Suite tiene punteros a sus objetos Test en un
	vector. Fíjese en la especificación de la excepción en
	la función addTest( ). Cuando añada una prueba a una suite,
	Suite::addTest( ) verifique que el puntero que pasa no sea null;
	si es null, se lanza una excepción TestSuiteError. Puesto que
	esto hace imposible añadir un puntero null a una suite,
	addSuite( ) afirma esta condición en cada prueba, como hacen
	las otras funciones que atraviesan el vector de pruebas (vea
	la siguiente implementación). Copiar y asignar están
	desestimados como están en la clase Test.
      </para>


<example>
<title></title>
<programlisting language="C++">
<xi:include parse="text" href="./code_v2/TestSuite/Suite.cpp"/>
</programlisting>
</example>


      <!--
      We will be using the TestSuite framework wherever it applies
      throughout the rest of this book.
      -->
      <para>
	Usaremos el framework TestSuite donde sea pertinente a lo largo
	del resto de este libro.
      </para>

    </sect2>
  </sect1>
  <sect1>
    <!-- : Debugging techniques -->
    <title>Técnicas de depuración </title>

    <!--
    The best debugging habit is to use assertions as explained in the
    beginning of this chapter; by doing so you'll help find logic errors
    before they cause real trouble. This section contains some other tips
    and techniques that might help during debugging.
    -->
    <para>
      La mejor costumbre para eliminar fallos es usar aserciones como
      se explica al principio de este capítulo; haciendo esto le
      ayudará a encontrar errores lógicos antes de que causen
      problemas reales. Esta sección contiene otros consejos y
      técnicas que podrían ayudar durante la depuración.
    </para>

    <sect2>
      <!-- : Trace macros -->
      <title>Macros de seguimiento </title>

      <!--
      Sometimes it's useful to print the code of each statement as it is
      executed, either to cout or to a trace file. Here's a preprocessor
      macro to accomplish this:
      -->
      <para>
	Algunas veces es útil imprimir el código de cada sentencia
	cuando es ejecutada, o cout o trazar un fichero. Aquí esta una
	macro de preprocesaor para llevar a cabo esto:
      </para>

      <!-- #define TRACE(ARG) cout &lt;&lt; #ARG &lt;&lt; endl; ARG -->
      <para>
	#define TRACE(ARG) cout &lt;&lt; #ARG &lt;&lt; endl; ARG
      </para>

      <!--
      Now you can go through and surround the statements you trace with this
      macro. However, this can introduce problems. For example, if you take
      the statement:
      -->
      <para>
	Ahora puede ir a través y alrededor de las sentencias que
	traceé con esta macro. Sin embargo, esto puede introducir
	problemas. Por ejemplo, si coge la sentencia:
      </para>

      <!--
      for(int i = 0; i  &lt; 100; i++)
      cout &lt;&lt; i &lt;&lt; endl;
      -->
      <para>
      for(int i = 0; i &lt; 100; i++)
      cout &lt;&lt; i &lt;&lt; endl;
      </para>

      <!-- and put both lines inside TRACE( ) macros, you get this: -->
      <para>
	y ponga ambas líneas dentro de la macro TRACE( ), obtiene esto:
      </para>

      <!--
      TRACE(for(int i = 0; i < 100; i++))
      TRACE(  cout &lt;&lt; i &lt;&lt; endl;)
      -->
      <para>
      TRACE(for(int i = 0; i  &lt; 100; i++))
      TRACE(  cout &lt;&lt; i &lt;&lt; endl;)
      </para>

      <!-- which expands to this: -->
      <para>
	que se expande a esto:
      </para>

      <!--
      cout &lt;&lt; "for(int i = 0; i < 100; i++)" &lt;&lt; endl;
      for(int i = 0; i < 100; i++)
      cout &lt;&lt; "cout &lt;&lt; i &lt;&lt; endl;" &lt;&lt; endl;
      cout &lt;&lt; i &lt;&lt; endl;
      -->
      <para>
      cout &lt;&lt; "for(int i = 0; i &lt; 100; i++)" &lt;&lt; endl;
      for(int i = 0; i &lt; 100; i++)
      cout &lt;&lt; "cout &lt;&lt; i &lt;&lt; endl;" &lt;&lt; endl;
      cout &lt;&lt; i &lt;&lt; endl;
      </para>


      <!--
      which isn't exactly what you want. Thus, you must use this technique
      carefully.
      -->
      <para>
	que no es exactamente lo que quiere. Por lo tanto, debe usar
	esta técnica cuidadosamente.
      </para>

      <!-- The following is a variation on the TRACE( ) macro: -->
      <para>
	Lo siguiente es una variación en la macro TRACE( ):
      </para>

      <!-- #define D(a) cout &lt;&lt; #a "=[" &lt;&lt; a &lt;&lt; "]" &lt;&lt; endl; -->
      <para>
	#define D(a) cout &lt;&lt; #a "=[" &lt;&lt; a &lt;&lt; "]" &lt;&lt; endl;
      </para>

      <!--
      If you want to display an expression, you simply put it inside a call
      to D( ). The expression is displayed, followed by its value (assuming
      there's an overloaded operator &lt;&lt; for the result type). For example,
      you can say D(a + b). You can use this macro any time you want to
      check an intermediate value.
      -->
      <para>
	Si quiere mostrar una expresión, simplemente póngala dentro de
	una llamada a D( ). La expresión se muestra, seguida de su
	valor ( asumiendo que hay un operador sobrecargado &lt;&lt; para el
	tipo de resultado). Por ejemplo, puede decir D(a + b). Puede
	usar esta macro en cualquier momento que quiera comprobar un
	valor intermedio.
      </para>

      <!--
      These two macros represent the two most fundamental things you do with
      a debugger: trace through the code execution and display values. A
      good debugger is an excellent productivity tool, but sometimes
      debuggers are not available, or it's not convenient to use
      them. These techniques always work, regardless of the situation.
      -->
      <para>
	Estas dos macros representan las dos cosas fundamentales que
	hace con un depurador: trazar la ejecución de código y
	mostrar valores. Un buen depurador es una herramienta de
	productividad excelente, pero a veces los depuradores no están
	disponibles, o no es conveniente usarlos. Estas técnicas
	siempre funcionan, sin tener en cuenta la situación.
      </para>

    </sect2>
    <sect2>
      <!-- : Trace file -->
      <title>Fichero de rastro </title>
      <!--
      DISCLAIMER: This section and the next contain code which is officially
      unsanctioned by the C++ Standard. In particular, we redefine cout and
      new via macros, which can cause surprising results if you're not
      careful. Our examples work on all the compilers we use, however, and
      provide useful information. This is the only place in this book where
      we will depart from the sanctity of standard-compliant coding
      practice. Use at your own risk! Note that in order for this to work, a
      using-declaration must be used, so that cout isn't prefixed by its
      namespace, i.e. std::cout will not work.
      -->
      <para>
	ADVERTENCIA: Esta sección y la siguiente contienen código que
	está oficialmente sin aprobación por el Estándar C++. En
	particular, redefinimos cout y new mediante macros, que puede
	provocar resultados sorprendentes si no tiene
	cuidado. Nuestros ejemplos funcionan en todos los compiladores
	que usamos, comoquiera, y proporcionan información útil. Este
	es el único lugar en este libro donde nos desviaremos de la
	inviolabilidad de la práctica de codificar cumpliendo el
	estándar. ¡Úsalo bajo tu propio riesgo! Dese cuenta que para
	este trabajo, usar delcaraciones debe ser realizado, para que
	cout no esté prefijado por su nombre de espacio,
	p.e. std::cout no funcionará.
      </para>

      <!--
      The following code easily creates a trace file and sends all the
      output that would normally go to cout into that file. All you must do
      is #define TRACEON and include the header file (of course, it's
      fairly easy just to write the two key lines right into your file):
      -->
      <para>
	El siguiente código crea fácilmente un fichero de seguimiento
	y envía todas las salidas que irían normalmente a cout a ese
	fichero. Todo lo que debe hacer es #define TRACEON e incluir
	el fichero de cabecera (por supuesto, es bastante fácil sólo
	escribir las dos líneas claves correctamente en su fichero):
      </para>


//: V2C03:Trace.h


      <!-- Here's a simple test of the previous file: -->
      <para>
	Aquí esta una prueba sencilla del fichero anterior:
      </para>


//: V2C03:Tracetst.cpp {-bor}

      <!--
      Because cout has been textually turned into something else by Trace.h,
      all the cout statements in your program now send information to the
      trace file. This is a convenient way of capturing your output into a
      file, in case your operating system doesn't make output redirection
      easy.
      -->
      <para>
	Porque cout ha sido textualmente convertido en algo más por
	Trace.h, todas las sentencias cout en su programa ahora envían
	información al fichero de seguimiento. Esto es una forma
	conveniente de capturar su salida en un fichero, en caso de
	que su sistema operativo no haga una fácil redirección de la salida.
      </para>

    </sect2>
    <sect2>
      <!-- : Finding memory leaks -->
      <title>Encontrar agujeros en memoria </title>

      <!--
      The following straightforward debugging techniques are explained in
      Volume 1:
      -->
      <para>
	Las siguientes técnicas sencillas de depuración están
	explicadas en el Volumen 1:
      </para>

      <!--
      1.  For array bounds checking, use the Array template in
      C16:Array3.cpp of Volume 1 for all arrays. You can turn off the
      checking and increase efficiency when you're ready to ship. (Although
      this doesn't deal with the case of taking a pointer to an array.)
      -->
      <para>
	1. Para comprobar los límites de un array, usa la plantilla
	Array en C16:Array3.cpp del Volumen 1 para todos los
	arrays. Puede desactivar la comprobación e incrementar la
	eficiencia cuando esté listo para enviar. (Aunque esto no trata
	con el caso de coger un puntero a un array.)
      </para>

      <!--
      2.  Check for non-virtual destructors in base classes.  Tracking
      new/delete and malloc/free
      -->
      <para>
	2. Comprobar destructores no virtuales en clases
	base. Seguirle la pista a new/delete y malloc/free
      </para>

      <!--
      Common problems with memory allocation include mistakenly calling
      delete for memory that's not on the free store, deleting the free
      store more than once, and, most often, forgetting to delete a
      pointer. This section discusses a system that can help you track down
      these kinds of problems.
      -->
      <para>
	Los problemas comunes con la asignación de memoria incluyen
	llamadas por error a delete para memoria que no está libre,
	borrar el espacio libre más de una vez, y más a menudo,
	olvidando borrar un puntero. Esta sección discute un sistema
	que puede ayudarle a localizar estos tipos de problemas.
      </para>

      <!--
      As an additional disclaimer beyond that of the preceding section:
      because of the way we overload new, the following technique may not
      work on all platforms, and will only work for programs that do not
      call the function operator new( ) explicitly. We have been quite
      careful in this book to only present code that fully conforms to the
      C++ Standard, but in this one instance we're making an exception for
      the following reasons:
      -->
      <para>
	Como cláusula adicional de exención de responsabilidad más
	allá de la sección precedente: por el modo que sobrecargamos
	new, la siguiente técnica puede no funcionar en todas las
	plataformas, y funcionará sólo para programas que no llaman
	explicitamente al operador de función new( ). Hemos sido
	bastante cuidadosos en este libro para presentar sólo código
	que se ajuste completamente al Estándar C++, pero en este
	ejemplo estamos haciendo una excepción por las siguientes
	razones:
      </para>

      <!--
      1.  Even though it's technically illegal, it works on many
      compilers.[29]
      -->
      <para>
	1. A pesar de que es técnicamente ilegal, funciona en muchos
	compiladores.[29]
      </para>

      <!-- 2.  We illustrate some useful thinking along the way. -->
      <para>
	2. Ilustramos algunos pensamientos útiles en el trascurso del
	camino.
      </para>

      <!-- To use the memory checking system, you simply include the
      header file MemCheck.h, link the MemCheck.obj file into your
      application to intercept all the calls to new and delete, and
      call the macro MEM_ON( ) (explained later in this section) to
      initiate memory tracing. A trace of all allocations and
      deallocations is printed to the standard output (via
      stdout). When you use this system, all calls to new store
      information about the file and line where they were called. This
      is accomplished by using the placement syntax for operator
      new.[30] Although you typically use the placement syntax when
      you need to place objects at a specific point in memory, it can
      also create an operator new( ) with any number of
      arguments. This is used in the following example to store the
      results of the __FILE__ and __LINE__ macros whenever new is
      called: -->
      <para>
	Para usar el sistema de comprobación de memoria, simplemente
	incluya el fichero de cabecera MemCheck.h, conecte el fichero
	MemCheck.obj a su aplicación para interceptar todas las
	llamadas a new y delete, y llame a la macro MEM_ON( )
	(se explica más tarde en esta sección) para iniciar el
	seguimiento de la memoria. Un seguimiento de todas las
	asignaciones y desasignaciones es impreso en la salida
	estándar (mediante stdout). Cuando use este sistema, todas las
	llamadas a new almacenan información sobre el fichero y la
	línea donde fueron llamados. Esto está dotado usando la
	sintaxis de colocación para el operador new.[30] Aunque
	normalmente use la sintaxis de colocación cuando necesite
	colocar objetos en un punto de memoria específico, puede
	también crear un operador new( ) con cualquier número de
	argumentos. Esto se usa en el siguiente ejemplo para almacenar
	los resultados de las macros __FILE__ y __LINE__ cuando se
	llama a new:
      </para>


//: V2C02:MemCheck.h


<!-- #REVISAR#  -->
      <!-- It is important to include this file in any source file in
      which you want to track free store activity, but include it last
      (after your other #include directives). Most headers in the
      standard library are templates, and since most compilers use the
      inclusion model of template compilation (meaning all source code
      is in the headers), the macro that replaces new in MemCheck.h
      would usurp all instances of the new operator in the library
      source code (and would likely result in compile
      errors). Besides, you are only interested in tracking your own
      memory errors, not the library's. -->
      <para>
	Es importante incluir este fichero en cualquier fichero fuente
	en el que quiera seguir la actividad de la memoria libre, pero
	inclúyalo al final (después de sus otras directivas
	#include). La mayoría de las cabeceras en la biblioteca
	estándar son plantillas, y puesto que la mayoría de los
	compiladores usan el modelo de inclusión de compilación de
	plantilla (significa que todo el código fuente está en las
	cabeceras), la macro que reemplaza new en MemCheck.h usurpará
	todas las instancias del operador new en el código fuente de
	la biblioteca (y casi resultaría en errores de
	compilación). Además, está sólo interesado en seguir sus
	propios errores de memoria, no los de la biblioteca.
      </para>

      <!-- In the following file, which contains the memory tracking
      implementation, everything is done with C standard I/O rather
      than with C++ iostreams. It shouldn't make a difference, since
      we're not interfering with iostreams' use of the free store, but
      when we tried it, some compilers complained. All compilers were
      happy with the <cstdio> version. -->
      <para>
	En el siguiente fichero, que contiene la implementación del
	seguimiento de memoria, todo está hecho con C estándar I/O más
	que con iostreams C++. No debería influir, puesto
	que no estamos interfiriendo con el uso de iostream en la
	memoria libre, pero cuando lo intentamos, algunos compiladores
	se quejaron. Todos los compiladores estaban felices con la
	versión &lt;cstdio>.
      </para>


//: V2C02:MemCheck.cpp {O}


      <!--
      The Boolean flags traceFlag and activeFlag are global, so they can be
      modified in your code by the macros TRACE_ON( ), TRACE_OFF( ), MEM_ON(
      ), and MEM_OFF( ). In general, enclose all the code in your main( )
      within a MEM_ON( )-MEM_OFF( ) pair so that memory is always
      tracked. Tracing, which echoes the activity of the replacement
      functions for operator new( ) and operator delete( ), is on by
      default, but you can turn it off with TRACE_OFF( ). In any case, the
      final results are always printed (see the test runs later in this
      chapter).
      -->
      <para>
	Las banderas booleanas de traceFalg y activeFlag son globales,
	por lo que pueden ser modificados en su código por las macros
	TRACE_ON( ), TRACE_OFF( ), MEM_ON( ), y MEM_OFF( ). En
	general, encierre todo el código en su main( ) dentro una
	pareja MEM_ON( )-MEM_OFF( ) de modo que la memoria sea siempre
	trazada. Trazar, que repite la actividad de las funciones de
	sustitución por el operador new( ) y el operador delete( ), es
	por defecto, pero puede desactivarlo con TRACE_OFF( ). En
	cualquier caso, los resultados finales son siempre impresos
	(vea la prueba que se ejecuta más tarde en este capítulo).
      </para>

      <!--
      The MemCheck facility tracks memory by keeping all addresses allocated
      by operator new( ) in an array of Info structures, which also holds
      the file name and line number where the call to new occurred. To
      prevent collision with any names you have placed in the global
      namespace, as much information as possible is kept inside the
      anonymous namespace. The Sentinel class exists solely to call a static
      object destructor as the program shuts down. This destructor inspects
      memMap to see if any pointers are waiting to be deleted (indicating a
      memory leak).
      -->
      <para>
	La facilidad MemCheck rastrea la memoria guardando todas las
	direcciones asignadas por el operador new( ) en un array de
	estructuras Info, que también tiene el nombre del fichero y el
	número de línea donde la llamada new se encuentra. Para prevenir la
	colisión con cualquier nombre que haya colocado en el espacio
	de nombres global, tanta información como sea posible se guarda
	dentro del espacio de nombre anónimo. La clase Sentinel existe
	únicamente para llamar a un destructor de objetos con estático
	cuando el programa termina. Este destructor inspecciona memMap
	para ver si algún puntero está esperando a ser borrado
	(indicando una perdida de memoria).
      </para>

      <!--
      Our operator new( ) uses malloc( ) to get memory, and then adds the
      pointer and its associated file information to memMap. The operator
      delete( ) function undoes all that work by calling free( ) and
      decrementing nptrs, but first it checks to see if the pointer in
      question is in the map in the first place. If it isn't, either you'
      re trying to delete an address that isn't on the free store, or you'
      re trying to delete one that's already been deleted and removed from
      the map. The activeFlag variable is important here because we don't
      want to process any deallocations from any system shutdown
      activity. By calling MEM_OFF( ) at the end of your code, activeFlag
      will be set to false, and such subsequent calls to delete will be
      ignored. (That's bad in a real program, but our purpose here is to
      find your leaks; we're not debugging the library.) For simplicity, we
      forward all work for array new and delete to their scalar
      counterparts.
      -->
      <para>
	Nuestro operador new( ) usa malloc( ) para conseguir memoria,
	y luego añade el puntero y su información de fichero asociado
	a memMap. La función de operador delete( ) deshace todo el
	trabajo llamando a free( ) y decrementando nptrs, pero primero
	se comprueba para ver si el puntero en cuestión está en el mapa
	en el primer lugar. Si no es así, o reintenta borrar una
	dirección que no está en el almacén libre, o re intenta borrar
	la que ya ha sido borrada y eliminada del mapa. La variable
	activeFlag es importante aquí porque no queremos procesar
	ninguna desasignación de alguna actividad del cierre del
	sistema. Llamando a MEM_OFF( ) al final de su código, activeFlag
	será puesta a falso, y posteriores llamadas para borrar serán
	ignoradas. (Está mal en un programa real, pero nuestra
	intención aquí es encontrar agujeros, no está depurando la
	biblioteca.) Por simplicidad, enviamos todo el trabajo por
	array new y delete a sus homólogos escalares.
      </para>

      <!-- The following is a simple test using the MemCheck facility: -->
      <para>
	Lo siguiente es un test sencillo usando la facilidad MemCheck:
      </para>


//: V2C02:MemTest.cpp

      <!--
      This example verifies that you can use MemCheck in the presence of
      streams, standard containers, and classes that allocate memory in
      constructors. The pointers p and q are allocated and deallocated
      without any problem, but r is not a valid heap pointer, so the output
      indicates the error as an attempt to delete an unknown pointer:
      -->
      <para>
	Este ejemplo verifica que puede usar MemCheck en presencia
	de streams, contenedores estándar, y clases que asignan
	memoria en constructores. Los punteros p y q son asignados y
	desasignados sin ningún problema, pero r no es un puntero de
	pila válido, así que la salida indica el error como un intento
	de borrar un puntero desconocido:
      </para>

      <!--
      hello
      Allocated 4 bytes at address 0xa010778 (file: memtest.cpp, line: 25)
      Deleted memory at address 0xa010778
      Allocated 12 bytes at address 0xa010778 (file: memtest.cpp, line: 27)
      Deleted memory at address 0xa010778
      Attempt to delete unknown pointer: 0x1
      Allocated 8 bytes at address 0xa0108c0 (file: memtest.cpp, line: 14)
      Deleted memory at address 0xa0108c0
      No user memory leaks!
      -->
      <para>
      hola
      Asignados 4 bytes en la dirección 0xa010778 (fichero: memtest.cpp, línea: 25)
      Deleted memory at address 0xa010778
      Asignados 12 bytes en la dirección 0xa010778 (fichero: memtest.cpp, línea: 27)
      Memoria borrada en la dirección 0xa010778
      Intento de borrar puntero desconocido: 0x1
      Asignados 8 bytes en la dirección 0xa0108c0 (fichero: memtest.cpp, línea: 14)
      Memoria borrada en la dirección 0xa0108c0
      ¡No hay agujeros de memoria de usuario!
      </para>

      <!--
      Because of the call to MEM_OFF( ), no subsequent calls to operator
      delete( ) by vector or ostream are processed. You still might get some
      calls to delete from reallocations performed by the containers.
      -->
      <para>
	A causa de la llamada a MEM_OFF( ), no se procesan posteriores
	llamadas al operador delete( ) por vector o ostream. Todavía
	podría conseguir algunas llamadas a delete realizadas dsede
	reasignaciones por los contenedores.
      </para>

      <!--
      If you call TRACE_OFF( ) at the beginning of the program, the output
      is
      -->
      <para>
	Si llama a TRACE_OFF( ) al principio del programa, la salida es
      </para>

      <!--
      hello
      Attempt to delete unknown pointer: 0x1
      No user memory leaks!
      -->
      <para>
	Hola
	Intento de borrar puntero desconocido: 0x1
	¡No hay agujeros de memoria de usuario!
      </para>

    </sect2>
  </sect1>

  <sect1>
    <!-- : Summary -->
    <title>Resumen </title>

    <!--
    Much of the headache of software engineering can be avoided by being
    deliberate about what you're doing. You've probably been using
    mental assertions as you've crafted your loops and functions, even if
    you haven't routinely used the assert( ) macro. If you'll use
    assert( ), you'll find logic errors sooner and end up with more
    readable code as well. Remember to only use assertions for invariants,
    though, and not for runtime error handling.
    -->
    <para>
      Muchos de los dolores de cabeza de la ingenería del software
      pueden ser evitados reflexionando sobre lo que está
      haciendo. Probablemente ha estado usando aserciones mentales
      cuando ha navegado por sus blucles y funciones, incluso si no ha
      usado rutinariamente la macro assert( ). Si usa assert( ),
      encontrará errores lógicos más pronto y acabará con código más
      legible también. Recuerde usar solo aserciones para invariantes,
      aunque, no para el manejo de error en tiempo de ejecución.
    </para>

    <!--
    Nothing will give you more peace of mind than thoroughly tested
    code. If it's been a hassle for you in the past, use an automated
    framework, such as the one we've presented here, to integrate routine
    testing into your daily work. You (and your users!) will be glad you
    did.
    -->
    <para>
      Nada le dará más tranquilidad que código probado
      rigurosamente. Si ha sido un lío en el pasado, use un framework
      automatizado, como el que hemos presentado aquí, para integrar
      la rutina de pruebas en su trabajo diario. Usted (¡y sus usarios!)
      estarán contentos de que lo haga.
    </para>

  </sect1>
  <sect1>
    <!-- : Exercises -->
    <title>Ejercicios </title>

    <!--
    Solutions to selected exercises can be found in the electronic
    document The Thinking in C++ Volume 2 Annotated Solution Guide,
    available for a small fee from www.MindView.net.
    -->
    <para>
      Las soluciones para ejercicios seleccionados pueden encontrarse
      en el documento electrónico Pensar en C++ Volumen 2 Guía de
      Soluciones Comentadas disponible por una pequeña cuota en
      www.MindView.net.
    </para>

    <!--
    1.  Write a test program using the TestSuite Framework for the
    standard vector class that thoroughly tests the following member
    functions with a vector of integers: push_back( ) (appends an element
    to the end of the vector), front( ) (returns the first element in the
    vector), back( ) (returns the last element in the vector), pop_back( )
    (removes the last element without returning it), at( ) (returns the
    element in a specified index position), and size( ) (returns the
    number of elements). Be sure to verify that vector::at( ) throws a
    std::out_of_range exception if the supplied index is out of range.
    -->
    <para>
      1. Escriba un programa de prueba usando el Framework TestSuite
      para la clase estándar vector que prueba rigurosamente prueba
      las siguientes funciones con un vector de enteros: push_back( )
      (añade un elemento al final del vector) front( ) (devuelve el
      primer elemento en el vector), back( ) (devuelve el último elemento en
      el vector), pop_back( ) (elimina el último elemento sin
      devolverlo), at( ) (devuelve el elemento en una posición
      específica), y size( ) (devuelve el número de
      elementos). Asegúrese de verificar que vector::at( ) lanza una
      excepción std::out_of_range si el índice facilitado está fuera
      de rango.
    </para>

    <!--
    2.  Suppose you are asked to develop a class named Rational that
    supports rational numbers (fractions). The fraction in a Rational
    object should always be stored in lowest terms, and a denominator of
    zero is an error. Here is a sample interface for such a Rational
    class:
    -->
    <para>
      2. Supóngase que le piden desarrollar un clase llamada Rational
      que da soporte a números racionales (fracciones). La fracción
      en un objecto Rational debería siempre almacenarse en los
      términos más bajos, y un denominador de cero es un error. Aquí
      está una interfaz de ejemplo para esa clase Rational:
    </para>


//: V2C02:Rational.h {-xo}


    <!--
    Write a complete specification for this class, including
    preconditions, postconditions, and exception specifications.
    -->
    <para>
      Escriba una especificación completa para esta clase, incluyendo
      especificaciones de precondiciones, postcondiciones, y de excepción.
    </para>

    <!--
    3.  Write a test using the TestSuite framework that thoroughly tests
    all the specifications from the previous exercise, including testing
    exceptions.
    -->
    <para>
      3. Escriba un prueba usando el framework TestSuite que pruebe
      rigurosamente todas las especificaciones del ejercicio anterior,
      incluyendo probar las excepciones.
    </para>

    <!--
    4.  Implement the Rational class so that all the tests from the
    previous exercise pass. Use assertions only for invariants.
    -->
    <para>
      4. Implemente la clase Rational de modo que pase todas las pruebas
      del ejercicio anterior. Use aserciones sólo para las invariantes.
    </para>

    <!--
    5.  The file BuggedSearch.cpp below contains a binary search function
    that searches the range [beg, end) for what. There are some bugs in
    the algorithm. Use the trace techniques from this chapter to debug the
    search function.
    -->
    <para>
      5. El fichero BuggedSearch.cpp de abajo contiene un función de
      búsqueda binaria que busca para el rango [pedir, final). Hay
      algunos errores en el algoritmo. Use las técnicas de seguimiento
      de este capítulo para depurar la función de búsqueda.
    </para>
  </sect1>
</chapter>