diff --git a/_posts/2020-09-01-totw-140.md b/_posts/2020-09-01-totw-140.md index baab7057..bd679024 100644 --- a/_posts/2020-09-01-totw-140.md +++ b/_posts/2020-09-01-totw-140.md @@ -429,21 +429,20 @@ Some modern C++ features are not yet supported by some major compilers. static constexpr absl::string_view kHello = "Hello"; return kHello; } - + -2. For the `extern const` - [variables declared in header files](#extern-const-variable) the following +2. For the `extern const` [variables declared in header files](#extern-const-variable) the following approach to defining their values is valid according to the standard C++, and would in fact be preferrable to ABSL_CONST_INIT, but it is not yet supported by some compilers.
-    // Defined in foo.cc -- valid C++, but not supported by MSVC 19.
-    constexpr absl::string_view kOtherBufferName = "other example";
-    
+// Defined in foo.cc -- valid C++, but not supported by MSVC 19. +constexpr absl::string_view kOtherBufferName = "other example"; + - As a workaround for a `constexpr` variable in a `.cc` file you can provide - its value to other files through functions. +As a workaround for a `constexpr` variable in a `.cc` file you can provide +its value to other files through functions. ### Mistake #4: Improperly Initialized Constants @@ -455,72 +454,66 @@ depend on the value of `X`? Cyclic initialization dependencies can easily happen with global variables, especially with those we think of as constants. This is a pretty thorny area of the language in its own right. -[The style guide](https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables) +["Static and Global Variables" in the Style Guide](https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables) is an authoritative reference. Consider the above links required reading. With a focus on initialization of constants, the phases of initialization can be explained as: -1. **Zero initialization**. This is what initializes otherwise uninitialized - static variables to the "zero" value for the type (e.g. `0`, `0.0`, `'\0'`, - null, etc.). +#### Zero initialization +This is what initializes otherwise uninitialized static variables to the +"zero" value for the type (e.g. `0`, `0.0`, `'\0'`, null, etc.).
-    const int kZero;  // this will be zero-initialized to 0
-    const int kLotsOfZeroes[5000];  // so will all of these
-    
+const int kZero; // this will be zero-initialized to 0 +const int kLotsOfZeroes[5000]; // so will all of these + - Note that relying on zero initialization is fairly popular in C code but is - fairly rare and niche in C++. It is generally clearer to assign variables - explicit values, even if the value is zero, which brings us to... +Note that relying on zero initialization is fairly popular in C code but is +fairly rare and niche in C++. It is generally clearer to assign variables +explicit values, even if the value is zero, which brings us to... -1. **Constant initialization**. +#### Constant initialization
-    const int kZero = 0;  // this will be constant-initialized to 0
-    const int kOne = 1;   // this will be constant-initialized to 1
-    
+const int kZero = 0; // this will be constant-initialized to 0 +const int kOne = 1; // this will be constant-initialized to 1 + - Both "constant initialization" and "zero initialization" are called "static - initialization" in the C++ language standard. Both are always safe. +Both "constant initialization" and "zero initialization" are called "static +initialization" in the C++ language standard. Both are always safe. -1. **Dynamic initialization**. +#### Dynamic initialization
-    // This will be dynamically initialized at run-time to
-    // whatever ArbitraryFunction returns.
-    const int kArbitrary = ArbitraryFunction();
-    
- - Dynamic initialization is where most problems happen. The style guide - explains why at - https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables. - - Note that documents like the Google C++ style guide have historically - included dynamic initialization in the broad category of "static - initialization." The word "static" applies to a few different concepts in - C++, which can be confusing. "Static initialization" can mean - "initialization *of* static variables," which can include run-time - computation (dynamic initialization). The language standard uses the term - "static initialization" in a different, narrower, sense: initialization that - is done statically or at compile-time. +// This will be dynamically initialized at run-time to +// whatever ArbitraryFunction returns. +const int kArbitrary = ArbitraryFunction(); + + +Dynamic initialization is where most problems happen. The style guide explains +why at ["Static and Global Variables"](https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables). + +Note that documents like the Google C++ style guide have historically included +dynamic initialization in the broad category of "static initialization." The +word "static" applies to a few different concepts in C++, which can be confusing. +"Static initialization" can mean "initialization *of* static variables," which +can include run-time computation (dynamic initialization). The language standard +uses the term "static initialization" in a different, narrower, sense: +initialization that is done statically or at compile-time. ## Initialization Cheat Sheet Here is a super-quick constant initialization cheat sheet (not in header files): -1. `constexpr` guarantees safe constant initialization as well as safe - (trivial) destruction. Any `constexpr` variable is entirely fine when - defined in a `.cc` file, but is problematic in header files for reasons - explained earlier. -2. `ABSL_CONST_INIT` guarantees safe constant initialization. Unlike - `constexpr`, it does not actually make the variable `const`, nor does it - ensure the destructor is trivial, so care must still be taken when declaring - static variables with it. See again - https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables. -3. Otherwise, you're most likely best off using a static variable within a - function and returning it. See http://go/cppprimer#static_initialization, - and the "ordinary function" example shown earlier. +1. `constexpr` guarantees safe constant initialization as well as safe (trivial) destruction. Any `constexpr` variable is entirely fine when defined in a `.cc` file, but is problematic in header files for reasons explained earlier. +1. `ABSL_CONST_INIT` guarantees safe constant initialization. Unlike `constexpr`, it does not actually make the variable `const`, nor does it ensure the destructor is trivial, so care must still be taken when declaring static variables with it. See again ["Static and Global Variables" in the Style Guide](https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables). +1. Otherwise, you're most likely best off using a static variable within a function and returning it. See the "ordinary function" example shown earlier. + +## Conclusion + +The `inline` variable from C++17 can't come soon enough. Until then all we can +do is use the safe idioms that steer us clear of the rough edges. ## Further Reading and Collected Links @@ -530,7 +523,4 @@ Here is a super-quick constant initialization cheat sheet (not in header files): * http://en.cppreference.com/w/cpp/language/storage_duration (linkage rules) * http://en.cppreference.com/w/cpp/language/ub (Undefined Behavior) -## Conclusion - -The `inline` variable from C++17 can't come soon enough. Until then all we can -do is use the safe idioms that steer us clear of the rough edges. +## Footnotes