-
Notifications
You must be signed in to change notification settings - Fork 319
/
bsls_assert.h
2431 lines (2261 loc) · 106 KB
/
bsls_assert.h
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
// bsls_assert.h -*-C++-*-
#ifndef INCLUDED_BSLS_ASSERT
#define INCLUDED_BSLS_ASSERT
#include <bsls_ident.h>
BSLS_IDENT("$Id: $")
//@PURPOSE: Provide build-specific, runtime-configurable assertion macros.
//
//@CLASSES:
// bsls::Assert: namespace for "assert" management functions
// bsls::AssertFailureHandlerGuard: scoped guard for changing handlers safely
// bsls::AssertViolation: attributes describing a failed assertion
//
//@MACROS:
// BSLS_ASSERT: runtime check typically enabled in non-opt build modes
// BSLS_ASSERT_SAFE: runtime check typically only enabled in safe build modes
// BSLS_ASSERT_OPT: runtime check typically enabled in all build modes
// BSLS_ASSERT_INVOKE: for directly invoking the current failure handler
// BSLS_ASSERT_INVOKE_NORETURN: direct invocation always marked to not return
//
//@SEE_ALSO: bsls_review, bsls_asserttest
//
//@DESCRIPTION: This component provides three "assert-like" macros,
// 'BSLS_ASSERT', 'BSLS_ASSERT_SAFE', and 'BSLS_ASSERT_OPT', that can be used
// to enable optional *redundant* runtime checks in corresponding build modes.
// If an assertion argument evaluates to 0, a runtime-configurable "handler"
// function is invoked with a 'bsls::AssertViolation', a value-semantic class
// that encapsulates the current filename, line number, level of failed check,
// and (0-valued expression) argument text.
//
// The class 'bsls::Assert' provides functions for manipulating the globally
// configured "handler". A scoped guard for setting and restoring the assert
// handler is provided by 'bsls::AssertFailureHandlerGuard'.
//
// An additional macro, 'BSLS_ASSERT_INVOKE', is provided for direct invocation
// of the current assertion failure handler. This macro is always enabled
// (i.e., regardless of build mode).
//
///Defensive Programming (DP)
///--------------------------
// Although there is no one agreed-upon definition, in this context we will use
// the term *Defensive* *Programming* (DP) to mean any attempt by the component
// author to provide (optional) runtime validation of the preconditions (or
// invariants) defined in the function-level documentation (contract) for that
// component. Note that DP is intended to help expose defects early in the
// development process, and *never* to mask or recover from them in production.
//
// Calling a function without satisfying its preconditions results in
// *undefined* *behavior*. Detecting and reporting undefined behavior due to
// client misuse can sometimes be very helpful at identifying subtle errors.
// Additionally, we may choose to embed redundant (i.e., logically superfluous)
// runtime checks -- both as a form of active documentation, and also to help
// expose our own, latent coding errors that have escaped detection during
// testing. In either case, these *defensive* (and other) runtime checks can
// add significant overhead. Hence, this extra runtime overhead should not
// necessarily be incorporated for every build target and assertion mode (see
// "Build Modes" below). Moreover, the extent of these checks may change
// (i.e., for a particular build mode) from one release to the next.
// Therefore, any defensive (or other redundant) checks provided for a
// particular build mode are *NEVER* part of the function-level contract -- and
// remain solely what is known as a *Quality-of-Implementation* (QoI) issue.
//
///Assertion Semantics
///-------------------
// There are three important aspects of assertions: (1) !Every! !assertion!
// !is! !redundant!; it is essential that if all assertions are compiled out of
// a program that is defect-free, apart from improved runtime performance, the
// program behaves identically. Hence, (2) !each! !boolean-valued! !assert!
// !argument! !must! !have! !no! !side-effects!. Finally, (3) !assertions!
// !do! !not! !affect! !binary! !compatibility!; hence, translation units with
// different assertion levels (but not necessarily build targets) can safely be
// combined into a single program (see "Build Modes" and "Assertions in Header
// Files" below). Note that the build target 'BDE_BUILD_TARGET_SAFE_2' does
// permit binary incompatibility for conditionally compiled source code, but
// there is no corresponding 'BSLS_ASSERT_SAFE_2' assertion macro (see {Usage}
// below).
//
///Assertion Modes
///---------------
// Depending on the build, assertion macros can expand in 3 different ways:
//
//: 1 A 'bsls_assert' macro is "enabled in assert mode", or simply "enabled" if
//: it expands to check its predicate and call the assert failure handler
//: when it is false.
//:
//: 2 A 'bsls_assert' macro is "enabled in review mode", or simply "in review
//: mode" if it expands to check its predicate and call the *review* failure
//: handler when it is false. This is identical to a 'bsls_review' macro of
//: the same level when it is enabled.
//:
//: 3 A 'bsls_assert' macro is "disabled" if it expands to do nothing,
//: producing no executed code in the compiled program.
//
///Review Mode
///-----------
// The ability to enable assertions in review mode allows clients to easily and
// safely test, in a production environment, whether assertions having a lower
// threshold than what they currently have deployed are being triggered
// (without terminating the application). It is intended as an interim step
// towards lowering the assertion level threshold for an existing application.
// See {'bsls_review'} for a more detailed description of the behavior of
// assertions in review mode and suggested workflows for using this behavior.
//
///Detailed Behavior
///-----------------
// If an assertion fires (i.e., due to a 0-valued expression argument in an
// assert macro that is enabled or in review mode), there is a violation of the
// contract that the assertion is checking. If the assertion is enabled, the
// goal of the assertion is to report the precise location and nature of the
// defect *quickly* and *loudly* and prevent continued execution of the calling
// function past that point. If the assertion is in review mode then the
// behavior will match the corresponding 'bsls_review' macro and execution
// might continue, which has a priority of just logging the failure location.
//
// When enabled, the assert macros will all do essentially the same thing: Each
// macro tests the predicate expression 'X', and if '!(X)' is 'true', invokes
// the currently installed assertion failure handler. An instance of
// 'bsls::AssertViolation' will be created and populated with a textual
// rendering of the predicate ('#X'), the current '__FILE__', the current
// '__LINE__', and a string representing which particular type of assertion has
// failed. This 'violation' is then passed to the currently installed
// assertion failure handler (a function pointer with the type
// 'bsls::Assert::ViolationHandler' having the signature:
//..
// void(const bsls::AssertViolation&);
//..
//
// On some (currently experimental) platforms with support for some form of the
// upcoming language-level contract facilities there is also the ability to
// configure the assertion macros to introduce an assumption of the truth of
// their predicate. With this option the predicate will not neccesarily even
// be evaluated, and if it were to return false the compiler will treat the
// situation as undefined behavior ("impossible"). This mode for assertions
// can lead to improved code generation, but be aware that the potential
// downside of being wrong about the truth of your assertions is unbounded, and
// so deploying applications built with any assertions assumed should be done
// with great care - there are no guarantees about anything a program will do
// when an assumed assertion is violated.
//
///Selecting Which ASSERT Macro to Use
///-----------------------------------
// The choice of which specific macro to use is governed primarily by the
// impact that enabling the assertion (in either assert mode or review mode)
// will have on the runtime performance of the function, and in some cases on
// the size of the function.
//
//: 1 BSLS_ASSERT_SAFE - This macro should be reserved for tests incurring an
//: expensive change to the performance of a function, either a very high
//: constant time increase in execution time of the function, or an increase
//: in the algorithmic complexity of a function. Note especially that a
//: change in algorithmic complexity breaks the documented contract of many
//: functions (e.g., an 'O(n)' check in a function with a documented
//: 'O(log(n))' runtime speed) and so checks with that level of cost should
//: be reserved for diagnostic use in "safe" builds.
//:
//: 2 BSLS_ASSERT - For "inexpensive" checks with only a constant factor
//: overhead. The majority of checks should fall into this category.
//:
//: 3 BSLS_ASSERT_OPT - For "negligible" checks that have little to no
//: measurable overhead on a function. This will often be the case for
//: argument checking in larger functions, or very simple checks in smaller
//: functions. Keep in mind that these checks will be enabled in all
//: typically deployed build modes, so they should be reserved for larger
//: functions and functions that will not be called in highly performance
//: critical code.
//
///Assertion and Review Levels
///---------------------------
// There are a few macros available to control which of the 'bsls_assert'
// macros are disabled, enabled in review mode, or enabled in assert mode (see
// {Assertion Modes} above). These macros are for the compilation and build
// environment to provide and are not themselves defined by BDE code -- e.g.,
// by supplying one or more of these macros with '-D' options on the compiler
// command line. In general, these macros are used to determine an
// 'ASSERT_LEVEL' that can be (from most aggressive/optimized to safest)
// 'ASSUME_SAFE', 'ASSUME_ASSERT', 'ASSUME_OPT', 'NONE', 'ASSERT_OPT',
// 'ASSERT', or 'ASSERT_SAFE'. Separately, a 'REVIEW_LEVEL' is determined that
// can be 'NONE', 'REVIEW_OPT', 'REVIEW', or 'REVIEW_SAFE'. Depending on these
// levels, the various 'bsls_assert' macros will be enabled, in review mode,
// assumed, or disabled. Macros up to the assert level will be enabled. If
// the review level is higher than the assert level then macros up to the
// review level (and above the assert level) will be enabled in review mode.
// Finally, macros higher than both the review level and the assert level will
// be disabled. If the review level is 'NONE' and the assert level is set to
// one of the assume levels, then macros that would be disabled up to the
// assumed level are instead assumed. If there is a review level set then no
// macros will ever be assumed. The following table illustrates this:
//..
// ===========================================
// Macro Instantiation Based on Review Level
// ===========================================
// ENABLED - Assertion is enabled (in "assert mode")
// REVIEW - Assertion is enabled (in "review mode")
// ASSUMED - Assertion is assumed (if supported)
// <blank> - Assertion is ignored
// -----------BSLS... LEVELS---------- ----------BSLS_.. MACROS---------
// BSLS_ASSERT_LEVEL BSLS_REVIEW_LEVEL ASSERT_OPT ASSERT ASSERT_SAFE
// ----------------- ----------------- ---------- ---------- -----------
// ASSUME_SAFE NONE ASSUMED ASSUMED ASSUMED
// ASSUME_ASSERT NONE ASSUMED ASSUMED
// ASSUME_OPT NONE ASSUMED
// NONE NONE
// NONE (or ASSUME*) REVIEW_OPT REVIEW
// NONE (or ASSUME*) REVIEW REVIEW REVIEW
// NONE (or ASSUME*) REVIEW_SAFE REVIEW REVIEW REVIEW
// ASSERT_OPT NONE ENABLED
// ASSERT_OPT REVIEW_OPT ENABLED
// ASSERT_OPT REVIEW ENABLED REVIEW
// ASSERT_OPT REVIEW_SAFE ENABLED REVIEW REVIEW
// ASSERT NONE ENABLED ENABLED
// ASSERT REVIEW_OPT ENABLED ENABLED
// ASSERT REVIEW ENABLED ENABLED
// ASSERT REVIEW_SAFE ENABLED ENABLED REVIEW
// ASSERT_SAFE NONE ENABLED ENABLED ENABLED
// ASSERT_SAFE REVIEW_OPT ENABLED ENABLED ENABLED
// ASSERT_SAFE REVIEW ENABLED ENABLED ENABLED
// ASSERT_SAFE REVIEW_SAFE ENABLED ENABLED ENABLED
//..
// See {'bsls_review'} for the logic that determines the review level. The
// logic that determines the assertion level checks a few different macros.
// The first check is for one of the 7 mutually exclusive 'BSLS_ASSERT_LEVEL'
// macros that can explicitly set the assert level:
//..
// MACRO BSLS_ASSERT_LEVEL
// ----- ----------------
// BSLS_ASSERT_LEVEL_ASSUME_SAFE ASSUME_SAFE
// BSLS_ASSERT_LEVEL_ASSUME_ASSERT ASSUME_ASSERT
// BSLS_ASSERT_LEVEL_ASSUME_OPT ASSUME_OPT
// BSLS_ASSERT_LEVEL_NONE NONE
// BSLS_ASSERT_LEVEL_ASSERT_OPT ASSERT_OPT
// BSLS_ASSERT_LEVEL_ASSERT ASSERT
// BSLS_ASSERT_LEVEL_ASSERT_SAFE ASSERT_SAFE
//..
// If none of these are defined, the assert level is determined by the build
// mode. With "safer" build modes we incorporate higher level defensive
// checks. A particular build mode is implied by the relevant (BDE) build
// targets that are defined at compilation (preprocessing) time. The following
// table shows the three (BDE) build targets that can affect the assertion and
// review levels:
//..
// (BDE) Build Targets
// -----------------------
// (A) BDE_BUILD_TARGET_SAFE_2
// (B) BDE_BUILD_TARGET_SAFE
// (C) BDE_BUILD_TARGET_OPT
//..
// *Any* of the 8 possible combinations of the three build targets is valid:
// e.g., 'BDE_BUILD_TARGET_OPT' and 'BDE_BUILD_TARGET_SAFE_2' may both be
// defined. The following table shows the assert level that is set depending
// on which combination of build target macros have been set:
//..
// =========================================================
// "ASSERT" Level Set With no Level-Overriding Flags defined
// =========================================================
// --- BDE_BUILD_TARGET ---- BSLS_ASSERT_LEVEL
// _SAFE_2 _SAFE _OPT
// ------- ------- ------- -----------------
// ASSERT
// DEFINED ASSERT_OPT
// DEFINED ASSERT_SAFE
// DEFINED DEFINED ASSERT_SAFE
// DEFINED ASSERT_SAFE
// DEFINED DEFINED ASSERT_SAFE
// DEFINED DEFINED ASSERT_SAFE
// DEFINED DEFINED DEFINED ASSERT_SAFE
//..
// As the table above illustrates, with no build target explicitly defined the
// assert level defaults to 'ASSERT'. If only 'BDE_BUILD_TARGET_OPT' is
// defined, the assert level will be set to 'ASSERT_OPT'. If either
// 'BDE_BUILD_TARGET_SAFE' or 'BDE_BUILD_TARGET_SAFE_2' is defined then the
// assert level is set to 'ASSERT_SAFE' and ALL assert macros will be enabled.
//
///Runtime-Configurable Assertion-Failure Behavior
///-----------------------------------------------
// In addition to the three (BSLS) "ASSERT" macros, 'BSLS_ASSERT',
// 'BSLS_ASSERT_SAFE', and 'BSLS_ASSERT_OPT', and the immediate invocation
// macro 'BSLS_ASSERT_INVOKE', this component provides (1) an 'invokeHandler'
// method used (primarily) to implement these "ASSERT" macros and enable their
// runtime configuration, (2) administration methods to configure, at runtime,
// the behavior resulting from an assertion failure (i.e., by installing an
// appropriate assertion-failure handler function), and (3) a suite of standard
// ("off-the-shelf") assertion-failure handler functions, to be installed via
// the administrative methods (if desired), and invoked by the 'invokeHandler'
// method on an assertion failure.
//
// When an enabled assertion fails, the currently installed *failure* *handler*
// ("callback") function is invoked. The default handler is the ('static')
// 'bsls::Assert::failByAbort' method; a user may replace this default handler
// by using the ('static') 'bsls::Assert::setViolationHandler' administrative
// method and passing it (the address of) a function whose signature conforms
// to the 'bsls::Assert::ViolationHandler' 'typedef'. This handler may be one
// of the other handler methods provided in 'bsls::Assert', or a new "custom"
// function, written by the user (see {Usage} below).
//
///Exception-Throwing Failure Handlers and 'bsls::AssertFailureHandlerGuard'
///-------------------------------------------------------------------------
// Among the failure handlers provided is 'bsls::Assert::failByThrow', which
// throws a 'bsls::AssertTestException' object. Throwing an exception,
// however, is not safe in all environments and deliberately aborting is more
// useful in a debugging context than throwing an unhandled exception. Hence,
// in order for an 'bsls::AssertTestException' object to be thrown on an
// assertion failure, the user must first install the
// 'bsls::Assert::failByThrow' handler (or another exception-throwing handler)
// explicitly.
//
// Note that an object of type 'bsls::AssertFailureHandlerGuard' can be used to
// temporarily set an exception-throwing handler within a 'try' block,
// automatically restoring the previous handler when the 'try' block exits (see
// {Usage} below).
//
///Assertion Handler Policy
///------------------------
// Bloomberg policy is that (by default) tasks may not install an assertion
// handler that returns control to the point immediately following the
// detection of a failed assertion. So an assertion handler may, for example,
// terminate the task or throw an exception, but may not log the problem and
// return. 'bsls_assert', by default, enforces that policy by terminating the
// task if an installed assertion handler function chooses to returns normally.
//
///Configuring an Exception to the Assertion Handler Policy
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 'bsls_assert' provides a two-part mechanism to permit returning after the
// detection of failed assertions.
//
// It is a violation of Bloomberg policy to modify this default configuration
// without permission from senior management. (Internal Bloomberg users should
// contact the BDE team if you feel your application needs an exception to this
// policy).
//
// The intention is to provide a means to override the assertion failure policy
// that can be enabled quickly, but requires the explicit (and obvious) choice
// from both the owner of the application's 'main' function, and the person
// responsible for building the application. In order to enable a policy
// exception, 'permitOutOfPolicyReturningFailureHandler' must be called, and
// the task must be linked with a special build of 'bsls_assert.o' (in which
// the 'k_permitOutOfPolicyReturningAssertionBuildKey' constant has the value
// "bsls-PermitOutOfPolicyReturn").
//
///Legacy Handler Functions
///------------------------
// Prior to the introduction of 'bsls::AssertViolation', the signature for
// 'bsls::Assert::ViolationHandler' was this:
//..
// void(const char*, const char*,int)
//..
// This signature for a handler is still supported (though deprecated) under
// its original name 'bsls::Assert::Handler'. Overloads that take a
// 'bsls::Assert::Handler' exist for 'bsls::AssertFailureHandler' and the
// constructor for 'bsls::AssertFailureHandlerGuard', so code that uses the old
// handler signature should work without changes.
//
// If a legacy handler is set as the current handler, the function
// 'bsls::Assert::failureHandler()' will return a pointer to that function,
// while 'bsls::Assert::violationHandler()' will return an internal function
// that extracts the appropriate arguments from the generated
// 'bsls::AssertViolation' object and passes them to the installed 'Handler'.
//
///Assertions in Header Files (Mixing Build Options Across Translation Units)
///--------------------------------------------------------------------------
// Mixing build modes across translation units, although not strictly
// conformant with the C++ language standard, is permissible in practice;
// however, the defensive checks that are enabled may be unpredictable. The
// *one-definition* *rule* states that if there are multiple definitions of an
// object or function within a program, these definitions *must* be identical
// or else the program is *ill-formed*. Unfortunately, definitions in header
// files may not be identical across object ('.o') files if the build targets
// or assertion-level flags defined during translation (preprocessing) are not
// the same.
//
// For example, consider an 'inline' function that sets the width of a 'Square'
// and optionally checks for (defends against) a negative 'width' argument:
//..
// // our_square.h
// // ...
//
// inline
// void Square::setWidth(int width)
// {
// BSLS_ASSERT_SAFE(width >= 0);
//
// d_width = width;
// }
//..
// Now consider a client that uses this 'setWidth' method:
//..
// // my_client.cpp
// // ...
// void f()
// {
// Square s;
// s.setWidth(-5);
// }
//..
// We can build the 'our_square' component in "safe mode" -- e.g., by
// incorporating '-DBSLS_ASSERT_LEVEL_ASSERT_SAFE' on the (Unix) command line.
// Notice, however, that building client software against a version of
// 'our_square.o' compiled in "safe mode" does *not* ensure that all of the
// 'BSLS_ASSERT_SAFE' macros will be active (will instantiate); instead, the
// client's build mode will (most likely) govern those instantiations of the
// 'BSLS_ASSERT_SAFE' macro located within the library. The only way to ensure
// that all of the 'BSLS_ASSERT_SAFE' macros instantiate is to build the
// *client* as well as the library software in "safe mode".
//
// Inline functions are not the only source of multiple inconsistent
// definitions. Consider a non-'inline' method 'reserveCapacity' on a 'List'
// template, parameterized by element 'TYPE':
//..
// // our_list.h
// // ...
//
// template <class TYPE>
// void List<TYPE>::reserveCapacity(int numElements)
// {
// BSLS_ASSERT(numElements >= 0);
// // ...
// }
//..
// Each different translation unit that invokes 'reserveCapacity' potentially
// generates another instantiation of this function template. Those
// translation units that are compiled in "debug mode" (or "safe mode") --
// e.g., with 'BSLS_ASSERT_LEVEL_ASSERT' (or 'BSLS_ASSERT_LEVEL_ASSERT_SAFE')
// defined -- will incorporate code corresponding to each use of the
// 'BSLS_ASSERT' macro therein; the rest will not. Which one of these template
// instantiations the linker uses in the final program is undefined and highly
// unpredictable.
//
// The bottom line is that, unless clients of a library are compiled with (at
// least) the same level of assertion enabling as the library itself, not all
// of the library's defensive checking (for the assertion-level for which the
// library was compiled) will necessarily be incorporated into the client code.
// Similarly, compiling a client in a higher-level of defensive checking (e.g.,
// "safe mode") than the library was compiled (e.g., "debug mode") may result
// in additional defensive checks beyond what the library author intended for
// the mode (e.g., "debug mode") in which the library was compiled.
//
// Note that all build modes (except for when 'BDE_BUILD_TARGET_SAFE_2' is
// defined, see below) are required to be binary compatible (e.g., fields
// cannot be added to the middle of a 'struct'). Since a component's contract
// makes no explicit promise about what checking will occur, that contract is
// not violated when different parts of a program are compiled with different
// levels of assertion-enabling build options. The only consequence is that a
// smaller (or larger) number of defensive checks may be active than might
// otherwise be expected.
//
///Conditional Compilation
///-----------------------
// To recap, there are three (mutually compatible) general *build* *targets*:
//: o 'BDE_BUILD_TARGET_OPT'
//: o 'BDE_BUILD_TARGET_SAFE'
//: o 'BDE_BUILD_TARGET_SAFE_2'
// seven (mutually exclusive) component-specific *assertion* *levels*:
//: o 'BSLS_ASSERT_LEVEL_ASSERT_SAFE'
//: o 'BSLS_ASSERT_LEVEL_ASSERT'
//: o 'BSLS_ASSERT_LEVEL_ASSERT_OPT'
//: o 'BSLS_ASSERT_LEVEL_NONE'
//: o 'BSLS_ASSERT_LEVEL_ASSUME_OPT'
//: o 'BSLS_ASSERT_LEVEL_ASSUME_ASSERT'
//: o 'BSLS_ASSERT_LEVEL_ASSUME_SAFE'
// and four (mutually exclusive) component-specific *review* *levels*:
//: o 'BSLS_REVIEW_LEVEL_REVIEW_SAFE'
//: o 'BSLS_REVIEW_LEVEL_REVIEW'
//: o 'BSLS_REVIEW_LEVEL_REVIEW_OPT'
//: o 'BSLS_REVIEW_LEVEL_NONE'
// The above macros can be defined (externally) by the build environment to
// affect which of the three *assert* *macros*:
//: o 'BSLS_ASSERT_SAFE(boolean-valued expression)'
//: o 'BSLS_ASSERT(boolean-valued expression)'
//: o 'BSLS_ASSERT_OPT(boolean-valued expression)'
// will be enabled in assert mode, which will be in review mode, which will be
// assumed, and which will be disabled.
//
// The public interface of this component also explicitly provides a number of
// additional intermediate macros to identify how the various 'BSLS_ASSERT'
// macros have been instantiated. These each exist for each level and have the
// following suffixes and meanings:
//: o 'IS_ACTIVE': Defined if the corresponding level is enabled in assert or
//: review mode. For example, 'BSLS_ASSERT_SAFE_IS_ACTIVE' is defined if
//: (and only if) the conditions expressed using 'BSLS_ASSERT_SAFE' will be
//: checked at runtime (either as assertions or reviews).
//: o 'IS_REVIEW': Defined if the corresponding level is enabled in review
//: mode.
//: o 'IS_ASSUMED': Defined if the corresponding level is assumed.
//: o 'IS_USED': Defined if assert expressions for the corresponding level need
//: to be valid (i.e., if they are "ODR-used"). For example,
//: 'BSLS_ASSERT_SAFE_IS_USED' is defined if (and only if) the conditions
//: expressed using 'BSLS_ASSERT_SAFE' will be compiled. Note that this is a
//: super-set of the cases where 'BSLS_ASSERT_SAFE_IS_ACTIVE' will be
//: defined, which is when the conditions will be checked at runtime, while
//: 'BSLS_ASSERT_SAFE_IS_USED' is also defined if the conditions are assumed
//: or if 'BSLS_ASSERT_VALIDATE_DISABLED_MACROS' is defined.
//
// Putting that together, these 3 macros are defined if the corresponding macro
// is in assert or review mode - and thus the expression will be checked and a
// violation handler will be invoked on failure:
//: o 'BSLS_ASSERT_SAFE_IS_ACTIVE'
//: o 'BSLS_ASSERT_IS_ACTIVE'
//: o 'BSLS_ASSERT_OPT_IS_ACTIVE'
// These three are defined if the corresponding macro is in review mode - and
// thus the expression will be checked and the review violation handler will be
// invoked on failure. These will be defined when the review level has been
// set to a level higher than the assert level:
//: o 'BSLS_ASSERT_SAFE_IS_REVIEW'
//: o 'BSLS_ASSERT_IS_REVIEW'
//: o 'BSLS_ASSERT_OPT_IS_REVIEW'
// These three are defined if the corresponding macro is being assumed, and it
// will be hard undefined behavior to violate these expressions:
//: o 'BSLS_ASSERT_SAFE_IS_ASSUMED'
//: o 'BSLS_ASSERT_IS_ASSUMED'
//: o 'BSLS_ASSERT_OPT_IS_ASSUMED'
//
// Finally, three more macros with the 'IS_USED' suffix are defined when the
// expression for the corresponding macro is going to be compiled. This will
// be true for macros in assert, review or assumed modes, and it will be true
// for all macros if 'BSLS_ASSERT_VALIDATE_DISABLED_MACROS' has been defined.
//: o 'BSLS_ASSERT_SAFE_IS_USED'
//: o 'BSLS_ASSERT_IS_USED'
//: o 'BSLS_ASSERT_OPT_IS_USED'
//
// Note that any of the 'IS_ACTIVE', 'IS_REVIEW", and 'IS_ASSUMED' macros being
// defined will imply that the corresponding 'IS_USED' macro is also defined.
//
// Which of these macros to use to conditionally compile supporting code is
// based on when that supporting code needs to be compiled:
//: o Use '#if defined(..._IS_USED)' when:
//: * Writing functions that are only accessible to and needed for assertions
//: of the corresponding level. This could be private member functions,
//: static functions, or functions in an anonymous namespace. See
//: {Example 8} for details on this use.
//: o Use '#if !defined(..._IS_ACTIVE) && !defined(..._IS_ASSUMED)' when:
//: * You are writing (test) code that will intentionally violate a contract
//: when there is not going to be any intrinsic ill effect to that
//: violation. Generally this should only be required when there is a need
//: to validate out-of-contract behavior of a component from within its own
//: test driver.
//: o Use '#if defined(...IS_ACTIVE)' when:
//: * You are doing negative testing and want to be sure that when you call
//: your function out of contract that the violation handler will be
//: invoked. See {'bsls_asserttest'} for tools to do this without having
//: to manually check these macros.
//: * Writing redundant defensive code that should only execute when the
//: corresponding assertions are going to be enabled. The assertion itself
//: should also be included in the same preprocessor block. See
//: {Example 9} for details on this use.
//: * Note that historically this was the only macro available, and it is
//: often used for blocks of code where the checks above would be more
//: appropriate. This can often lead to code that fails to compile with
//: 'BSLS_ASSERT_VALIDATE_DISABLED_MACROS' enabled or which will not work
//: correctly when assumptions are turned on.
//
// See {Example 6} and {Example 7}, respectively, for how
// 'BDE_BUILD_TARGET_SAFE_2' and intermediate assertion predicate macros, such
// as 'BSLS_ASSERT_SAFE_IS_ACTIVE' (and even 'BSLS_ASSERT_OPT_IS_ACTIVE'), can
// be used profitably in practice.
//
///Validating Disabled Macro Expressions
///-------------------------------------
// An additional external macro, 'BSLS_ASSERT_VALIDATE_DISABLED_MACROS', can be
// defined to control the compile time behavior of 'bsls_assert'. Enabling
// this macro configures all *disabled* assert macros to still instantiate
// their predicates (in a non-evaluated context) to be sure that the predicate
// is still syntactically valid. This can be used to ensure assertions that
// are rarely enabled have valid expressions.
//
///Language-Level Contracts
///------------------------
// Contracts were proposed, accepted into the draft C++20 standard, and then
// removed. Implementations of that facility exist and it is expected future
// implementations will begin to arrive as work on new proposals comes to
// fruition. Defining the macro 'BSLS_ASSERT_USE_CONTRACTS' will cause all
// 'BSLS_ASSERT' (and, if possible, 'BSLS_REVIEW') macros to go through the
// language-level contract implementation if it is available (currently only on
// an experimental version of the gcc-compiler), otherwise a diagnostic will be
// issued.
//
// Note that mixing builds that do and do not use 'BSLS_ASSERT_USE_CONTRACTS'
// is not supported. Attempting to link against a library bult with a
// different mode for this option will cause a link-time error.
//
///Usage
///-----
// The following examples illustrate (1) when to use each of the three kinds of
// (BSLS) "ASSERT" macros, (2) when and how to call the 'invokeHandler' method
// directly, (3) how to configure, at runtime, the behavior resulting from an
// assertion failure using "off-the-shelf" handler methods, (4) how to create
// your own custom assertion-failure handler function, (5) proper use of
// 'bsls::AssertFailureHandlerGuard' to install, temporarily, an
// exception-producing assert handler, (6) how "ASSERT" macros would be used in
// conjunction with portions of the source code (affecting binary
// compatibility) that are incorporated only when 'BDE_BUILD_TARGET_SAFE_2' is
// defined, and (7) how assertion predicates (e.g.,
// 'BSLS_ASSERT_SAFE_IS_ACTIVE') are used to conditionally compile additional
// (redundant) defensive source code (not affecting binary compatibility)
// precisely when the corresponding (BSLS) "ASSERT" macro (e.g.,
// 'BSLS_ASSERT_SAFE') is active.
//
///Example 1: Using 'BSLS_ASSERT', 'BSLS_ASSERT_SAFE', and 'BSLS_ASSERT_OPT'
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// This component provides three different variants of (BSLS) "ASSERT" macros.
// This first usage example illustrates how one might select each of the
// particular variants, based on the runtime cost of the defensive check
// relative to that of the useful work being done.
//
// Use of the 'BSLS_ASSERT_SAFE' macro is often appropriate when the defensive
// check occurs within the body of an 'inline' function. The
// 'BSLS_ASSERT_SAFE' macro minimizes the impact on runtime performance as it
// is instantiated only when requested (i.e., by building in "safe mode"). For
// example, consider a light-weight point class 'Kpoint' that maintains 'x' and
// 'y' coordinates in the range '[-1000 .. 1000]':
//..
// my_kpoint.h
// ...
//
// class Kpoint {
// short int d_x;
// short int d_y;
// public:
// Kpoint(short int x, short int y);
// // ...
// // The behavior is undefined unless '-1000 <= x <= 1000' and
// // '-1000 <= y <= 1000'.
// // ...
// };
//
// ...
//..
// Since the cost of validation here is significant compared with the useful
// work being done, we might choose to implement defensive checks using
// 'BSLS_ASSERT_SAFE' as follows:
//..
// ...
//
// inline
// Kpoint::Kpoint(short int x, short int y)
// : d_x(x)
// , d_y(y)
// {
// BSLS_ASSERT_SAFE(-1000 <= x); BSLS_ASSERT_SAFE(x <= 1000);
// BSLS_ASSERT_SAFE(-1000 <= y); BSLS_ASSERT_SAFE(y <= 1000);
// }
//..
// For more substantial (non-'inline') functions, we would be more likely to
// use the 'BSLS_ASSERT' macro because the runtime overhead due to defensive
// checks is likely to be much less significant. For example, consider a
// hash-table class that allows the client to resize the underlying table:
//..
// my_hashtable.h
// ...
//
// class HashTable {
// // ...
// public:
// // ...
//
// void resize(double loadFactor);
// // Adjust the size of the underlying hash table to be approximately
// // the current number of elements divided by the specified
// // 'loadFactor'. The behavior is undefined unless
// // '0 < loadFactor'.
// };
//..
// Since the relative runtime cost of validating the input argument is quite
// small (e.g., less than 10%) compared to the typical work being done, we
// might choose to implement the defensive check using 'BSLS_ASSERT' as
// follows:
//..
// my_hashtable.cpp
// ...
//
// void HashTable::resize(double loadFactor)
// {
// BSLS_ASSERT(0 < loadFactor);
//
// // ...
// }
//..
// In some cases, the runtime cost of checking is always negligible when
// compared with the runtime cost of performing the useful work; moreover, the
// consequences of continuing in an undefined state for certain applications
// could be catastrophic. Instead of using 'BSLS_ASSERT' in such cases, we
// might consider using 'BSLS_ASSERT_OPT'. For example, suppose we have a
// financial application class 'TradingSystem' that performs trades:
//..
// my_tradingsystem.h
// ...
//
// class TradingSystem {
// // ...
// public:
// // ...
//..
// Further suppose that there is a particular method 'executeTrade' that takes,
// as a scaling factor, an integer that must be a multiple of 100 or the
// behavior is undefined (and might actually execute a trade):
//..
// void executeTrade(int scalingFactor);
// // Execute the current trade using the specified 'scalingFactor'.
// // The behavior is undefined unless '0 <= scalingFactor' and '100'
// // evenly divides 'scalingFactor'.
// // ...
// };
//..
// Because the cost of the two checks is likely not even measurable compared to
// the overhead of accessing databases and executing the trade, and because the
// consequences of specifying a bad scaling factor are virtually unbounded, we
// might choose to implement these defensive checks using 'BSLS_ASSERT_OPT' as
// follows:
//..
// my_tradingsystem.cpp
// ...
//
// void TradingSystem::executeTrade(int scalingFactor)
// {
// BSLS_ASSERT_OPT(0 <= scalingFactor);
// BSLS_ASSERT_OPT(0 == scalingFactor % 100);
//
// // ...
// }
//..
// Notice that in each case, the choice of which of the three (BSLS) "ASSERT"
// macros to use is governed primarily by the relative runtime cost compared
// with that of the useful work being done (and only secondarily by the
// potential consequences of continuing execution in an undefined state).
//
///Example 2: When and How to Call the 'invokeHandler' Method Directly
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// There *may* be times (but this is yet to be demonstrated) when we might
// reasonably choose to unconditionally invoke the currently installed
// assertion-failure handler directly -- i.e., instead of via one of the three
// (BSLS) "ASSERT" macros provided in this component. Suppose that we are
// currently in the body of some function 'someFunc' and, for whatever reason,
// feel compelled to invoke the currently installed assertion-failure handler
// based on some criteria other than the current build mode.
// 'BSLS_ASSERT_INVOKE' is provided for this purpose. The call might look as
// follows:
//..
// void someFunc(bool a, bool b, bool c)
// {
// bool someCondition = a && b && !c;
//
// if (someCondition) {
// BSLS_ASSERT_INVOKE("Bad News");
// }
// }
//..
// If presented with invalid arguments, 'someFunc' (above) will produce output
// similar to the following:
//..
// Assertion failed: Bad News, file bsls_assert.t.cpp, line 609
// Abort (core dumped)
//..
// If a piece of code needs to be guaranteed to not return, the additional
// macro 'BSLS_ASSERT_INVOKE_NORETURN' is also available. It behaves the same
// way as 'BSLS_ASSERT_INVOKE', but if the installed handler *does* return
// 'failByAbort' will be immediately called. On supported platforms it is
// marked appropriately to not return to support compiler requirements and
// static analysis tools.
//
///Example 3: Runtime Configuration of the 'bsls::Assert' Facility
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// By default, any assertion failure will result in the invocation of the
// 'bsls::Assert::failByAbort' handler function. We can replace this behavior
// with that of one of the other static failure handler methods supplied in
// 'bsls::Assert' as follows. Let's assume we are at the top of our
// application called 'myMain' (which would typically be 'main'):
//..
// void myMain()
// {
//..
// First observe that the default assertion-failure handler function is, in
// fact, 'bsls::Assert::failByAbort':
//..
// assert(&bsls::Assert::failByAbort == bsls::Assert::violationHandler());
//..
// Next, we install a new assertion-failure handler function,
// 'bsls::Assert::failBySleep', from the suite of "off-the-shelf" handlers
// provided as 'static' methods of 'bsls::Assert':
//..
// bsls::Assert::setViolationHandler(&bsls::Assert::failBySleep);
//..
// Observe that 'bsls::Assert::failBySleep' is the new, currently-installed
// assertion-failure handler:
//..
// assert(&bsls::Assert::failBySleep == bsls::Assert::violationHandler());
//..
// Note that if we were to explicitly invoke the current assertion-failure
// handler as follows:
//..
// BSLS_ASSERT_INVOKE("message"); // This will hang!
//..
// the program will hang since 'bsls::Assert::failBySleep' repeatedly sleeps
// for a period of time within an infinite loop. Thus, this assertion-failure
// handler is useful for hanging a process so that a debugger may be attached
// to it.
//
// We may now decide to disable the 'setViolationHandler' method using the
// 'bsls::Assert::lockAssertAdministration()' method to ensure that no one else
// will override our decision globally. Note, however, that the
// 'bsls::AssertFailureHandlerGuard' is not affected, and can still be used to
// supplant the currently installed handler (see below):
//..
// bsls::Assert::lockAssertAdministration();
//..
// Attempting to change the currently installed handler now will fail:
//..
// bsls::Assert::setViolationHandler(&bsls::Assert::failByAbort);
//
// assert(&bsls::Assert::failByAbort != bsls::Assert::violationHandler());
//
// assert(&bsls::Assert::failBySleep == bsls::Assert::violationHandler());
// }
//..
//
///Example 4: Creating a Custom Assertion Handler
/// - - - - - - - - - - - - - - - - - - - - - - -
// Sometimes, especially during testing, we may need to write our own custom
// assertion-failure handler function. The only requirements are that the
// function have the same prototype (i.e., the same respective parameter and
// return types) as the 'bsls::Assert::Handle' 'typedef', and that the function
// should not return (i.e., it must 'abort', 'exit', 'terminate', 'throw', or
// hang). To illustrate, we will create a 'static' method at file scope that
// conforms to the required structure (notice the explicit use of 'std::printf'
// from '<cstdio>' instead of 'std::cout' from '<iostream>' to avoid
// interaction with the C++ memory allocation layer):
//..
// static bool globalEnableOurPrintingFlag = true;
//
// static
// void ourFailureHandler(const bsls::AssertViolation& violation)
// // Print the expression 'comment', 'file' name, and 'line' number from
// // the specified 'violation' to 'stdout' as a comma-separated list,
// // replacing null string-argument values with empty strings (unless
// // printing has been disabled by the 'globalEnableOurPrintingFlag'
// // variable), then unconditionally abort.
// {
// const char *comment = violation.comment();
// if (!comment) {
// comment = "";
// }
// const char *file = violation.fileName();
// if (!file) {
// file = "";
// }
// int line = violation.lineNumber();
// if (globalEnableOurPrintingFlag) {
// std::printf("%s, %s, %d\n", comment, file, line);
// }
// std::abort();
// }
//..
// At the top level of our application we have the following:
//..
// void ourMain()
// {
//..
// First, let's observe that we can assign this new function to a function
// pointer of type 'bsls::Assert::Handler':
//..
// bsls::Assert::ViolationHandler f = &ourFailureHandler;
//..
// Now we can install it just as we would any other handler:
//..
// bsls::Assert::setViolationHandler(&ourFailureHandler);
//..
// We can now invoke the default handler directly:
//..
// BSLS_ASSERT_INVOKE("str1");
// }
//..
// With the resulting output something like as follows:
//..
// str1, my_file.cpp, 17
// Abort (core dumped)
//..
//
///Example 5: Using the 'bsls::AssertFailureHandlerGuard'
/// - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Sometimes we may want to replace, temporarily (i.e., within some local
// lexical scope), the currently installed assertion-failure handler function.
// In particular, we sometimes use the 'bsls::AssertFailureHandlerGuard' class
// to replace the current handler with one that throws an exception (because we
// know that such an exception is safe in the local context). Let's start with
// the simple factorial function below, which validates, in "debug mode" (or
// "safe mode"), that its input is non-negative:
//..
// double fact(int n)
// // Return 'n!'. The behavior is undefined unless '0 <= n'.
// {
// BSLS_ASSERT(0 <= n);
//
// double result = 1.0;
// while (n > 1) {
// result *= n--;
// }
// return result;
// }
//..
// Now consider the following integer-valued 'extern "C"' C++ function,
// 'wrapperFunc', which can be called from C and FORTRAN, as well as from C++:
//..
// extern "C" int wrapperFunc(bool verboseFlag)
// {
// enum { GOOD = 0, BAD } result = GOOD; (void) verboseFlag;
//..
// The purpose of this function is to allow assertion failures in subroutine
// calls below this function to be handled by throwing an exception, which is
// then caught by the wrapper and reported to the caller as a "bad" status.
// Hence, when within the runtime scope of this function, we want to install,
// temporarily, the assertion-failure handler 'bsls::Assert::failByThrow',
// which, when invoked, causes an 'bsls::AssertTestException' object to be
// thrown. (Note that we are not advocating this approach for "recovery", but
// rather for an orderly shut-down, or perhaps during testing.) The
// 'bsls::AssertFailureHandlerGuard' class is provided for just this purpose:
//..
// assert(&bsls::Assert::failByAbort == bsls::Assert::violationHandler());
//
// bsls::AssertFailureHandlerGuard guard(&bsls::Assert::failByThrow);
//
// assert(&bsls::Assert::failByThrow == bsls::Assert::violationHandler());
//..
// Next we open up a 'try' block, and somewhere within the 'try' we
// "accidentally" invoke 'fact' with an out-of-contract value (i.e., '-1'):
//..
// #ifdef BDE_BUILD_TARGET_EXC
// try
// #endif
// {
//
// // ...
//
// double d = fact(-1); // Out-of-contract call to 'fact'.
//
// // ...
// }
// #ifdef BDE_BUILD_TARGET_EXC
// catch (const bsls::AssertTestException& e) {
// result = BAD;
// if (verboseFlag) {
// std::printf( "Internal Error: %s, %s, %d\n",
// e.expression(),
// e.filename(),
// e.lineNumber() );
// }
// }
// #endif
// return result;
// }
//..
// Assuming exceptions are enabled (i.e., 'BDE_BUILD_TARGET_EXC' is defined),
// if an 'bsls::AssertTestException' occurs below this wrapper function, the
// exception will be caught, a message will be printed to 'stdout', e.g.,
//..
// Internal Error: bsls_assert.t.cpp:500: 0 <= n
//..
// and the 'wrapperFunc' function will return a bad status (i.e., 1) to its
// caller. Note that if exceptions are not enabled,
// 'bsls::Assert::failByThrow' will behave as 'bsls::Assert::failByAbort', and
// dump core immediately:
//..
// Assertion failed: 0 <= n, file bsls_assert.t.cpp, line 500
// Abort (core dumped)
//..
// Finally note that the 'bsls::AssertFailureHandlerGuard' is not thread-aware.
// In particular, a guard that is created in one thread will also affect the
// failure handlers that are used in other threads. Care should be taken when
// using this guard when more than a single thread is executing.
//
///Example 6: Using (BSLS) "ASSERT" Macros Along With 'BDE_BUILD_TARGET_SAFE_2'
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Recall that assertions do not affect binary compatibility; however, software
// built with 'BDE_BUILD_TARGET_SAFE_2' defined need not be binary compatible
// with software built otherwise. In this example, we look at how we might use
// the (BSLS) "ASSERT" family of macros in conjunction with code that is
// incorporated (at compile time) only when 'BDE_BUILD_TARGET_SAFE_2' is
// defined.
//
// As a simple example, let's consider an elided implementation of a
// singly-linked integer list and its iterator. Whenever
// 'BDE_BUILD_TARGET_SAFE_2' is defined, we want to defend against the
// possibility that a client mistakenly passes a 'ListIter' object into a
// 'List' object method (e.g., 'List::insert') where that 'ListIter' object did
// not originate from the same 'List' object.
//
// We'll start by defining a local helper 'List_Link' 'struct' as follows:
//..
// struct List_Link {
// List_Link *d_next_p;
// int d_data;
// List_Link(List_Link *next, int data) : d_next_p(next), d_data(data) { }
// };
//..
// Next, we'll define 'ListIter', which always identifies the current position
// in a sequence of links, but whenever 'BDE_BUILD_TARGET_SAFE_2' is defined,
// also maintains a pointer to its parent 'List' object:
//..
// class List; // Forward declaration.
//
// class ListIter {
// #ifdef BDE_BUILD_TARGET_SAFE_2
// List *d_parent_p; // Exists only in "safe 2 mode".