-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcodingguide.xml
3747 lines (3418 loc) · 195 KB
/
codingguide.xml
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
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="styleguide.xsl"?>
<GUIDE title="STAR C++ Coding Guidelines">
<address>
Authors:<br/>
Mustafa Mustafa <br/>
Thomas Ullrich <br/>
Anselm Vossen <br/>
</address>
<address><p><em>Version 1.0, June 24, 2015</em></p></address>
<CATEGORY title="Introduction">
<p>
This is a document of the C++ coding guidelines compiled for the STAR
collaboration by the above mentioned authors. This effort was initiated by the STAR
computing coordinator Jerome Lauret on October 31, 2014. The charge can be
viewed <a href="charge.txt">here</a>. The committee produced two documents, one for the
coding guidelines seen here, and one for the naming and formatting guidelines that
can be viewed <a href="formatguide.xml">here</a>.
</p>
<p>
The committee based their work on the existing guidelines, expanded them for clarity, and
added new material where it saw fit. The coding guidelines include the new C++11 standard.
We have made heavy use of the C++ Google Style guide at <a href="http://google-styleguide.googlecode.com">
http://google-styleguide.googlecode.com</a> using their xml and css style sheets.
</p>
<p>
The goal of this guide is to manage the complexity of C++ (often in conjunction with ROOT)
by describing
in detail the dos and don'ts of writing C++ code. These rules exist to
keep the STAR code base manageable while still allowing coders to use C++ language
features productively. In some cases
we constrain, or even ban, the use of certain C++ and ROOT features. We do this to
keep code simple and to avoid the various common errors and
problems that these features can cause. We also had to take into account that
millions of lines of STAR code exist. For a new experiment the guidelines certainly
would look different in places but we have to live with the legacy
of existing code and the guidelines under which they were written.
</p>
<p>
Note that this guide is not a C++ tutorial: we assume that the
reader is familiar with the language. We marked parts of the guidelines that address
specifically new C++11 features.
</p>
</CATEGORY>
<OVERVIEW>
<CATEGORY title="Important Note">
<STYLEPOINT title="Displaying Hidden Details in this Guide">
<SUMMARY>
This style guide contains many details that are initially
hidden from view. They are marked by the triangle icon, which you
see here on your left. The first level of hidden information is
the subsection <i>Summary</i> in each rule and the second level of hidden information is the
optional subsection <i>Extra details and exceptions to the rule</i>. Click the arrow on the
left now, you should see "Hooray" appear below.
</SUMMARY>
<BODY>
<p>
Hooray! Now you know you can expand points to get more
details. Alternatively, there are an "expand all summaries"
and an "expand all summaries and extra details" at the
top of this document.
</p>
</BODY>
</STYLEPOINT>
</CATEGORY>
</OVERVIEW>
<CATEGORY title="Header Files">
<p>
In general, every <code>.cxx</code> file should have an associated
<code>.h</code> file. Each header file should contain only one or related class declarations for maintainability and for easier retrieval of class definitions.
</p>
<p>
Correct use of header files can make a huge difference to the
readability, size and performance of your code.
The following rules will guide you through the various pitfalls of
using header files.
</p>
<STYLEPOINT title="The #define Guard">
<SUMMARY>
All header files should have <code>#define</code> guards to
prevent multiple inclusion. The format of the symbol name
should be
<code><i><FILE></i>_H</code>.
</SUMMARY>
<BODY>
<p>
For example, the file
<code>myFile.h</code> should
have the following guard:
</p>
<CODE_SNIPPET>
#ifndef MYFILE_H
#define MYFILE_H
...
#endif // MYFILE_H
</CODE_SNIPPET>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Forward Declarations">
<SUMMARY>
You may forward declare ordinary classes in order to avoid
unnecessary <code>#include</code>s.
</SUMMARY>
<BODY>
<DEFINITION>
A "forward declaration" is a declaration of a class, function,
or template without an associated definition. <code>#include</code>
lines can often be replaced with forward declarations of whatever
symbols are actually used by the client code.
</DEFINITION>
<PROS>
<ul>
<li>Unnecessary <code>#include</code>s force the compiler to open
more files and process more input.</li>
<li>They can also force your code to be recompiled more often, due
to changes in the header.</li>
</ul>
</PROS>
<CONS>
<ul>
<li>It can be difficult to determine the correct form of a
forward declaration in the presence of features like templates,
typedefs, default parameters, and using declarations.</li>
<li>Forward declaring multiple symbols from a header can be more
verbose than simply including the header.</li>
<li>Forward declarations of functions and templates can prevent
the header owners from making otherwise-compatible changes to
their APIs; for example, widening a parameter type, or adding
a template parameter with a default value.</li>
<li>Forward declaring symbols from namespace <code>std::</code>
usually yields undefined behavior.</li>
</ul>
</CONS>
<DECISION>
<ul>
<li>When using a function declared in a header file, always
<code>#include</code> that header.</li>
<li>When using a class template, prefer to <code>#include</code> its
header file.</li>
<li>When using an ordinary class, relying on a forward declaration
is OK, but be wary of situations where a forward declaration may
be insufficient or incorrect; when in doubt, just
<code>#include</code> the appropriate header.</li>
<li>Do not replace data members with pointers just to avoid an
<code>#include</code>.</li>
</ul>
Always <code>#include</code> the file that actually provides the
declarations/definitions you need; do not rely on the symbol being
brought in transitively via headers not directly included. One
exception is that <code>myFile.cxx</code> may rely on
<code>#include</code>s and forward declarations from its corresponding
header file <code>myFile.h</code>.
</DECISION>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Inline Functions">
<SUMMARY>
As a general rule, put function definitions into the <code>.cxx</code> file.
Short, compact member functions can be put in the header file <em>after</em> the class declaration
preceded by the <code>inline</code> keyword. Inlining virtual function is discouraged.
</SUMMARY>
<BODY>
<DEFINITION>
<p>
The inline keyword indicates that inline substitution of the function body at the point
of call is to be preferred to the usual function call mechanism.
But a compiler is not required to perform this inline substitution at the point of call.
</p>
</DEFINITION>
<SUBSECTION title="Discussion:">
<p>
Functions that are defined within a class definition are implicitly inline. Note, however, that the definition of functions in the class definition is strongly discouraged in STAR.
</p>
<p>
An inline function must be defined in every translation unit from where it is called.
It is undefined behavior if the definition of the inline function is not the same for all translation units.
Note that this implies that the function is defined in a header file.
This can have an impact on compile time and lead to longer (= less efficient) development cycles.
</p>
<p>
Note that the inline keyword has no effect on the linkage of a function.
Linkage can be changed via unnamed namespaces or the static keyword.
</p>
<p>
In general, virtual functions can only be inlined when the compiler can either prove that the static
type matches the dynamic type or when the compiler can safely determine the dynamic type. For example,
when you use a value of type A the compiler knows that the dynamic type cannot be different and it can
inline the function. When using a pointer or a reference the compiler generally cannot prove that the
static type is the same and virtual functions generally need to follow the usual virtual dispatch.
</p>
</SUBSECTION>
<DECISION>
<p>
If you add a new function, put it into the <code>.cxx</code> file per default.
Small functions, like accessors and mutators may be placed into the <code>.h</code> file instead (<code>inline</code>).
Also, most template function implementations need to go into the <code>.h</code> file.
If you later determine that a function should be moved from the <code>.cxx</code> file into the <code>.h</code> file, please make sure that it helps the compiler in optimizing the code.
Otherwise you're just increasing compile time.
</p>
<p>
The inlining of virtual functions is problematic. At least one virtual function must be outlined but we
advise to not inline virtual functions as a general rule.
This pins the vtable, which will otherwise cause a pile of unnecessary symbols.
</p>
</DECISION>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Names and Order of Includes">
<SUMMARY>
Include headers from external libraries using <b>angle brackets</b>. Include headers from your own project/libraries using <b>double quotes</b>.<br/>
Do not rely on implicit includes. Make header files self-sufficient. <br/>
</SUMMARY>
<BODY>
<p>
There are two types of #include statements: <code>#include <myFile.h></code> and <code>#include “myFile.h”</code>.
</p>
<ul>
<li> Include headers from external libraries using angle brackets.
<CODE_SNIPPET>
#include <iostream>
#include <cmath>
#include <TH1D.h>
</CODE_SNIPPET>
</li>
<li>
Include headers from your own project or any STAR related project using double quotes.
<CODE_SNIPPET>
#include "MyClass.h"
#include "StEnumeration.h"
</CODE_SNIPPET>
</li>
</ul>
<p>
The header files of external libraries are obviously not in the
same directory as your source files. So you need to use angle brackets.
</p>
<p>
Headers of your own application have a defined relative location to the source
files of your application. Using double quotes, you have to specify the correct
relative path to the include file.
</p>
<i>Include order </i>
<p>
Another important aspect of include management is the include order.
Typically, you have a class named Foo, a file Foo.h and a file Foo.cxx .
The rule is :
In your file Foo.cxx, you should include Foo.h as the first include, before the system
includes.
</p>
<p>
The rationale behind that is to make your header standalone.
</p>
<p>
Let's imagine that your Foo.h looks like this:
<BAD_CODE_SNIPPET>
class Foo
{
public:
Bar getBar();
};
</BAD_CODE_SNIPPET>
</p>
<p>
And your Foo.cxx looks like this:
<BAD_CODE_SNIPPET>
#include "Bar.h"
#include "Foo.h"
</BAD_CODE_SNIPPET>
</p>
<p>
Your Foo.cxx file will compile, but it will not compile for other people using Foo.h without including Bar.h.
Including Foo.h first makes sure that your Foo.h header works for others.
<CODE_SNIPPET>
// Foo.h
#include "Bar.h"
class Foo
{
public:
Bar getBar();
};
</CODE_SNIPPET>
<CODE_SNIPPET>
// Foo.cxx
#include "Foo.h"
</CODE_SNIPPET>
</p>
<p>
For more details: <a href="http://techbase.kde.org/Policies/Library_Code_Policy#Getting_.23includes_right">Getting #includes right</a>.
</p>
</BODY>
</STYLEPOINT>
</CATEGORY>
<CATEGORY title="Namespaces">
<p>
Namespaces subdivide the global scope into distinct, named
scopes, and thus are useful for logically grouping related types and functions and
preventing name collisions. In C++ it is in general very good practice to use namespaces,
especially in libraries. However, historically STAR software makes little to no use of namespaces
but rather uses a specific naming scheme (prefixes) to indicate the scope
(e.g. <code>StEmc</code>..., <code>StTpc</code>... etc). While certain tools in STAR can handle
namespaces (such as <code>cons</code>) others would be very cumbersome to adapt.
</p>
<STYLEPOINT title="General Guideline">
<SUMMARY>
Namespaces are for legacy reasons depreciated in STAR. As with every guideline there
might be exceptions, especially in end user code. However, care should be taken to check for
possible side effects. Namespaces should be entirely avoided in the context of <code>StEvent</code>.
</SUMMARY>
<BODY>
<p>
When using namespaces in end-user parts of your code (e.g. specific analysis code),
encapsulate your entire class into the namespace.
Nonmember functions that are logically tied to a specific type should be in the same namespace as that type.
To make namespace work with <code>cons</code> and ROOT use the STAR specific $NMSPC tag as follows
<CODE_SNIPPET>
namespace StMyStuff //$NMSPC
{
class AClass : public TNamed {...};
class BClass : public TNamed {...};
} // namespace StMyStuff
</CODE_SNIPPET>
This will cause cons to generate a dictionary consistent with ROOT. The tag
$NMSPC triggers the namespace inclusion (multiple namespaces can be used but
you cannot combine sections
with namespace and sections without).
</p>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Using Declarations and Directives">
<SUMMARY>
Don't write namespace using declarations or using directives
in a header file or before an #include.
</SUMMARY>
<BODY>
<p>
<CODE_SNIPPET>
# include "Bar.h"
// OK in .cxx after include statements
using namespace Foo;
// sometimes a using declaration is preferable, to be precise
// about the symbols that get imported
using Foo::Type;
</CODE_SNIPPET>
</p>
<p>
<BAD_CODE_SNIPPET>
// Forbidden in .h -- This pollutes the namespace.
using namespace Foo;
</BAD_CODE_SNIPPET>
</p>
<EXTRA>
The using directive can sometimes be useful in header files to import one namespace into another one.
This can effectively hide a namespace from the public interface, similar to what an inline namespace does.
</EXTRA>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="std Namespace">
<SUMMARY>
Do not declare anything in namespace <code>std</code>, not even forward
declarations of standard library classes. The only exception to this rule is template specialization (see below).
</SUMMARY>
<BODY>
<MOTIVATION>
<p>
Declaring entities in namespace <code>std</code> represents undefined behavior,
i.e., not portable. To declare entities from the standard library, include
the appropriate header file. One exception to this is template specialization, e.g. <code>std::hash<MyType></code>
needs to be in namespace <code>std</code>.
</p>
</MOTIVATION>
</BODY>
</STYLEPOINT>
</CATEGORY>
<CATEGORY title="Scoping">
<STYLEPOINT title="Nonmember and Global Functions" nobutton="yes">
<SUMMARY>
Avoid non-member function if possible. If it is a function that applies to several classes of similar type consider
making it a member of a base class.
</SUMMARY>
</STYLEPOINT>
<STYLEPOINT title="Local Variables">
<SUMMARY>
Declare variables as locally as possible.
</SUMMARY>
<BODY>
<MOTIVATION>
<p> Variables whose lifetime are longer than necessary have several
drawbacks:
<ul>
<li>They make the code harder to understand and maintain.</li>
<li>They can't be always sensibly initialized.</li>
</ul>
</p>
</MOTIVATION>
<EXTRA>
<ul>
<li>It can be sometimes more efficient to declare a variable (usually of an
object type) outside a loop.
<p>
If the variable is an object, its constructor is invoked every time
it enters scope and is created, and its destructor is invoked every
time it goes out of scope.
</p>
<BAD_CODE_SNIPPET>
// Inefficient implementation:
for (int i = 0; i < bigNumber; ++i) {
Foo foo; // My ctor and dtor get called bigNumber times each.
foo.doSomething(i);
}
</BAD_CODE_SNIPPET>
<p>
It may be more efficient to declare such a variable used in a
loop outside that loop:
</p>
<CODE_SNIPPET>
Foo foo; // My ctor and dtor get called once each.
for (int i = 0; i < bigNumber; ++i) {
foo.doSomething(i);
}
</CODE_SNIPPET>
</li>
<li> This item does not apply to constants, because constants don't add a state.
</li>
</ul>
</EXTRA>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Variables Initialization">
<SUMMARY>
Always initialize variables.<br/>
</SUMMARY>
<BODY>
<p>
Do not separate initialization from declaration, e.g.
</p>
<BAD_CODE_SNIPPET>
int value;
value = function(); // Bad -- initialization separate from declaration.
</BAD_CODE_SNIPPET>
<CODE_SNIPPET>
int value = function(); // Good -- declaration has initialization.
</CODE_SNIPPET>
<p>
Use a default initial value or ternary operator (?:) to reduce mixing data flow with control
flow.
</p>
<BAD_CODE_SNIPPET>
int speedupFactor; // Bad: does not initialize variable
if (condition) {
speedupFactor = NoFactor;
}
else {
speedupFactor = DoubleFactor;
}
</BAD_CODE_SNIPPET>
<CODE_SNIPPET>
int speedupFactor = DoubleFactor; // Good: initializes variable
if (condition) {
speedupFactor = NoFactor;
}
</CODE_SNIPPET>
<CODE_SNIPPET>
int speedupFactor = condition ? NoFactor : DoubleFactor; // Good: initializes variable
</CODE_SNIPPET>
<p>
Prefer declaration of loop variables inside a loop, e.g.
</p>
<BAD_CODE_SNIPPET>
int i; // Bad: does not initialize variable
for (i = 0; i < number; ++i) {
doSomething(i);
}
</BAD_CODE_SNIPPET>
<CODE_SNIPPET>
for (int i = 0; i < number; ++i) {
doSomething(i); // Good
}
</CODE_SNIPPET>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Brace Initialization" cpp11="yes">
<SUMMARY>
Prefer initialization with braces except for single-argument assignment. However, never use brace initialization with <code>auto</code>.
</SUMMARY>
<BODY>
<p>In C++11, the brace initialization syntax for builtin arrays and POD structures has been extended for use with all other datatypes.
<p> Example of brace initialization:
</p>
<CODE_SNIPPET>
std::vector<std::string> myVector{"alpha", "beta", "gamma"};
</CODE_SNIPPET>
</p>
<p>
Example of single-argument assignments:
</p>
<CODE_SNIPPET>
int value = 3; // preferred style
std::string name = "Some Name";
int value { 3 }; // also possible
std::string name{ "Some Name" };
std::string name = { "Some Name" };
</CODE_SNIPPET>
<p>
Brace initialization can be in particular useful to initialize class members.
</p>
<p>User data types can also define constructors that take
<code>initializer_list</code>, which is automatically created from
<i>braced-init-list</i>:
<CODE_SNIPPET>
#include <initializer_list>
class MyType
{
public:
// initializer_list is a reference to the underlying init list,
// so it can be passed by value.
MyType(std::initializer_list<int> initList) {
for (int element : initList) {...}
}
};
MyType myObject{2, 3, 5, 7};
</CODE_SNIPPET></p>
<p>Finally, brace initialization can also call ordinary constructors of
data types that do not have <code>initializer_list</code> constructors.
<CODE_SNIPPET>
// Calls ordinary constructor as long as MyOtherType has no
// initializer_list constructor.
class MyOtherType {
public:
explicit MyOtherType(std::string name);
MyOtherType(int value, std::string name);
};
MyOtherType object1 = {1, "b"};
// If the constructor is explicit, you can't use the "= {}" form.
MyOtherType object2{"b"};
</CODE_SNIPPET></p>
<p>Never assign a <i>braced-init-list</i> to an <code>auto</code> local variable.</p>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Global Variables">
<SUMMARY>
Variables declared in the global scope are not allowed. Other global variables, including
static class variables and variables in namespace scope, should be
avoided where other means of communication are possible.
</SUMMARY>
<BODY>
<DEFINITION>
A global variable is a variable that can be accessed (theoretically) from everywhere in the program.
The adjective "global" should rather be understood as concerning its linkage, not whether it is in the global scope.
<BAD_CODE_SNIPPET>
int gBar; // this is obviously global
class Something
{
private:
static int sId; // but this one too (details at the end of the rule)
};
namespace NotGlobalScope {
Foo fooObject; // and finally this one as well
}
</BAD_CODE_SNIPPET>
</DEFINITION>
<PROS>
Global variables are a simple solution to sharing of data.
</PROS>
<CONS>
Global variables make it harder to reason about the code (for humans and compilers):
the smaller the number of variables a given region of code reads and writes, the easier.
Global variables can be read and written from anywhere.
Therefore, global variables pose a challenge to the optimizer.
</CONS>
<DECISION>
We want to reduce the shared data in our software to the unavoidable minimum.
Therefore, global variables should be avoided where other means of communication are possible.
</DECISION>
<EXTRA>
Note that a private static class variable sId is global. For example two threads having
each an instance of the class could access sId via these instances.
</EXTRA>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Global Variables Initialization">
<SUMMARY>
In the rare and justified cases where you use global variables, including file-static variables, static member variables and variables in
namespace scope, initialize them statically.
</SUMMARY>
<BODY>
<DEFINITION>
<ul>
<li>This rule additionally applies to file-static variables.</li>
<li>A global variable is statically initialized if the type has no constructor or a <code>constexpr</code> constructor.
This is the case for fundamental types (integers, chars, floats, or pointers) and POD (Plain Old Data: structs/unions/arrays
of fundamental types or other POD structs/unions). </li>
</ul>
</DEFINITION>
<PROS>
Dynamic initialization of globals can be used to run code before <code>main()</code>.
Destructors of globals can be used to run code after <code>main()</code>.
Dynamic initialization of globals in dynamically loaded objects can be used to run code on plugin load.
</PROS>
<CONS>
It is very hard to reason about the order of execution of such functions.
Especially if dynamically initialized globals are present in shared libraries that are linked
into dynamically loaded objects, few people understand the semantics.
</CONS>
<p>
As an example do this:
</p>
<CODE_SNIPPET>
struct Pod {
int indexes[5];
float width;
};
struct LiteralType {
int value;
constexpr LiteralType() : value(1) {}
};
Pod gData;
LiteralType gOtherData;
</CODE_SNIPPET>
<p>
But not this :
</p>
<BAD_CODE_SNIPPET>
class NotPod {
NotPod();
};
NotPod gBadData; // dynamic constructor
</BAD_CODE_SNIPPET>
<!--
// a.cxx:
int gSomeValue = someFunction();
// b.cxx:
extern int gSomeValue;
int someOtherFunction() { return gSomeValue + 1; }
int gGlobalValue = someOtherFunction(); // it is undefined whether gGlobalValue
// will be 0 + 1 or someFunction() + 1
-->
<DECISION>
Global variables must be initialized statically. <br/>
We only allow global variables to contain POD data. This
rule completely disallows <code>std::vector</code> (use <code>std::array</code> instead), or
<code>std::string</code> (use <code>const char []</code>) for global variables.
</DECISION>
<EXTRA>
<p>
If there is a need for startup or shutdown code, dynamic constructors may be used. But only if:
<ul>
<li>The dependencies on other data are minimized.</li>
<li>It is documented what code depends on this and why there is no issue of incorrect calling order.</li>
<li>Side-effects are clearly understood and documented.</li>
</ul>
</p>
<p>
Example that exhibits the problem of execution order:
</p>
<BAD_CODE_SNIPPET>
// Struct.h:
#include <string>
struct Struct {
static std::string sString;
};
// Struct.cxx:
std::string Struct::sString = "Hello World";
// main.cxx:
#include "Struct.h"
#include <iostream>
std::string gAnotherString = Struct::sString;
int main() {
std::cout << gAnotherString << std::endl;
return 0;
}
</BAD_CODE_SNIPPET>
<p>
This program will either output "Hello World" or crash, depending on the initialization order (with GCC on Linux it depends on whether you link with <code>g++ Struct.o main.o</code> or <code>g++ main.o Struct.o</code>).
</p>
</EXTRA>
</BODY>
</STYLEPOINT>
</CATEGORY>
<CATEGORY title="Classes">
Classes are the fundamental unit of code in C++. Naturally, we use
them extensively. This section lists the main dos and don'ts you
should follow when writing a class.
<STYLEPOINT title="Constructors">
<SUMMARY>
Every class should have at least one constructor. All uninitialized variables should be initialized in the constructor.
</SUMMARY>
<BODY>
<p>Every class should have at least one constructor
even if it does nothing or is defined to do nothing, or compiler defaults should be <em>explicitly</em>
requested using the <code>default</code> specifier. This is good practice, it indicates to
the reader that the coder thought about this and not plainly forgot about it.</p>
<p>If a class does not have a constructor there is no guarantee of
how objects of that class will be initialized, whilst data members should be explicitly initialized therein. When
the constructor dynamically allocates memory, a destructor must be added to return the memory to the free pool
when an object gets cleaned up.</p>
In the constructor all data member should be initialized, either in the constructor function body or in the constructor initializer list
or in-class. See the next item for more.
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Initialization">
<SUMMARY>
Declare and initialize members variables in the same order.
Prefer initialization (in the constructor initializer list or in-class) to assignment (in the constructor function body).
</SUMMARY>
<BODY>
<CPP11 title="In-Class Member Initialization">
C++98 allows in-class member initialization for const static members only. C++11 allows in-class member initialization for any variable.
<CODE_SNIPPET>
class MyClass
{
public:
int x = 1;
};
</CODE_SNIPPET>
This is basically equivalent to using initialization lists in constructors. The advantage of in-class initialization is that it allows
consistent default initialization when there are multiple constructors and saves a lot of typing resulting in cleaner codes.
Constructor initialization overrides in-class initialization.
</CPP11>
<DEFINITION>
<p>
Class member variables are initialized in the order in which they are declared in the class definition.
The order in the constructor initializer list has no influence on initialization order and therefore may be misleading if it does not match the order of the declaration.
Compilers often issue a warning if this rule is broken, but not always.
</p>
<p>
If a member variable is not explicitly initialized in the constructor initializer list and it is a non-POD the default constructor of that variable is called.
Therefore, if a member variable is assigned to in the constructor function body, the member variable may get initialized unnecessarily with the default constructor.
If the variable is a POD and the class instance is created with the <code>new</code> operator the variable will be zero-initialized. Otherwise, PODs are left uninitialized
see examples below.
</p>
<p>
If you do not declare any constructors yourself then the compiler will generate a
default constructor for you, which may leave some fields uninitialized or
initialized to inappropriate values.
</p>
<p>
Examples:
</p>
<p>
Initialization list:
</p>
<CODE_SNIPPET>
// MyClass.h
class MyClass : public MyBase {
// ...
private:
int mValue;
std::vector mVector;
};
// MyClass.cxx
MyClass::MyClass() : MyBase(),
mValue(0),
mVector()
{}
</CODE_SNIPPET>
<p>
See an example of initialization via <code>std::initializer_list</code>
in <a href="#Brace_Initialization"> Brace Initialization</a>.
</p>
<p>
Non explicit initialization:
</p>
<CODE_SNIPPET>
struct MyStruct
{
int x;
myStruct(): x(10) {}
};
class MyClass
{
public:
int mX;
int mY;
MyStruct mS;
// mS and mY are not explicitly initialized in the initializer list
// mS default constructor will always be called.
// mY is a POD therefore it will be:
// Zero-initialized if instance of MyClass is created with new operator.
// Otherwise, left un-initialized.
MyClass(): mX(5) { cout << mX << " " << mS.x << " " << mY << endl; }
};
int main()
{
MyClass c0; // MyClass::mY will not be initialized.
MyClass* c1 = new MyClass(); // MyClass::mY will be zero-initialized.
MyClass* c2 = new MyClass; // MyClass::mY will be zero-initialized.
}
</CODE_SNIPPET>
</DEFINITION>
<DECISION>
<p>
Member variables should be declared and initialized in the same order.
</p>
<p>
Use in-class member initialization for simple initializations,
especially when a member variable must be initialized the same way
in more than one constructor.
</p>
<p>
If your class defines member variables that aren't
initialized in-class, and if it has no other constructors,
you must define a default constructor (one that takes no
arguments). It should preferably initialize the object in
such a way that its internal state is consistent and valid.
</p>
<p>
If your class inherits from an existing class but you add no
new member variables, you are not required to have a default
constructor, also see <a href="#Delegating_and_Inheriting_Constructors">Delegating and Inheriting Constructors</a>.
</p>
</DECISION>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Virtual Functions in Constructors and Destructors">
<SUMMARY>
Do not call virtual functions in constructors and destructors. <br/>
</SUMMARY>
<BODY>
<p>
Inside constructors and destructors virtual function do not
behave "virtually". If the work calls virtual functions, these calls
will not get dispatched to the subclass implementations.
Calls to an unimplemented pure virtual function result in undefined
behavior.
</p>
<p>
Calling a virtual function non-virtually is fine:
<BAD_CODE_SNIPPET>
class MyClass {
public:
MyClass() { doSomething(); } // Bad
virtual void doSomething();
};
</BAD_CODE_SNIPPET>
<CODE_SNIPPET>
class MyClass {
public:
MyClass() { MyClass::doSomething(); } // Good
virtual void doSomething();
};
</CODE_SNIPPET>
</p>
<DECISION>
Constructors should never call virtual functions.
</DECISION>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Copy Constructor and Assignment Operator">
<SUMMARY>
Each class should have an assignment operator and a copy constructor implemented or explicitly deleted. Exception is when the class doesn't allocate subsidiary
data structures on the heap, in this case compiler defaults can be explicitly requested. Be aware of data slicing for polymorphic classes.
</SUMMARY>
<BODY>
<CPP11 title="Control of Defaults: default and delete">
Since C++11, the programmer can instruct the compiler not to create certain defaults by using the specifier <code>= delete</code>
This is particularly useful in two cases:
1) Making objects non-copyable:
<CODE_SNIPPET>
class NonCopyable
{
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
};
</CODE_SNIPPET>
2) Preventing implicit conversion of function arguments:
<CODE_SNIPPET>
class MyClass
{
void f(double i);
void f(int) = delete;
};
</CODE_SNIPPET>
The specifier <code>= default</code> can be used to state the programmers wish for defaults to be created.
<CODE_SNIPPET>
class MyClass
{
MyClass() = default; // default constructor is explicitly requested.
MyClass(...);
};
</CODE_SNIPPET>
However, the verbosity here is redundant, it is useful as a declaration of intention.
For classes, the default generated functions are always public. Programmer can control the
visibility of the defaults by using <code>= default</code>.
</CPP11>
<DEFINITION>
The copy constructor and copy assignment operator are used to create copies of objects.
<p>
The assignment operator
<CODE_SNIPPET>
ClassName& operator=(const ClassName&)
</CODE_SNIPPET>
is called when one instance of a class is assigned to another.
The copy constructor
<CODE_SNIPPET>
ClassName(const ClassName&)
</CODE_SNIPPET>
defines the behavior of the class when it is passed by value as an argument, returned by
value from a function, or used to initialize one instance with the value of another class instance. Defining this
constructor, all the class objects are copied properly.
</p>
<p>It is possible to implement one using the other. One can safely invoke the copy assignment operator
from the constructor as long as the operator is not declared virtual.</p>
<SUBSECTION title="The Rule of Three">
<p>
The rule of three is a rule of thumb in C++ that claims that if a class defines one of the following it should probably explicitly define all three:
<ul>
<li>destructor</li>
<li>copy constructor</li>
<li>copy assignment operator</li>
</ul>
The Rule of Three claims that if one of these had to be defined by the programmer, it means that the compiler-generated version does not fit
the needs of the class in one case and it will probably not fit in the other cases either.</p>