当前位置:网站首页>Tips of this week 141: pay attention to implicit conversion to bool

Tips of this week 141: pay attention to implicit conversion to bool

2022-07-07 17:59:00 -Flying crane-

As TotW#141 Originally published in 2018 year 1 month 19 Japan
from Samuel Freilich A literary creation

Two null pointer checks

It is important to check whether the pointer is empty before dereferencing to avoid crashes and errors . This can be done in two ways :

if (foo) {
    
  DoSomething(*foo);
}
if (foo != nullptr) {
    
  DoSomething(*foo);
}

Whereas foo It's a pointer , These two conditions have the same semantics , But the later type check is more strict . stay C++ in , Many types can be implicitly converted to bool, When the pointed type itself is converted to bool Need extra attention when .

Consider the following code , It may have two distinct meanings :

bool* is_migrated = ...;

//  This is testing is_migrated Is it empty , Or the real intention is to verify *is_migrated It's true ?
if (is_migrated) {
    
  ...
}

This code is clearer :

//  It looks like it's for a bool* Null pointer to check 
if (is_migrated != nullptr) {
    
  ...
}

These two styles are in Google C++ Code is acceptable . So when the underlying type cannot be implicitly converted to bool when , Follow the style of the surrounding code . If the value in question is like std::unique_ptr In this way “ Intelligent pointer ”, Then the semantics and trade-offs are the same .

Optional values and scope distribution

Optional ( for example absl::optional) Is it worth it ? They deserve more careful consideration .
for example :

absl::optional<bool> b = MaybeBool();
if (b) {
     ... }  //  When the function returns absl::optional(false) What happened ?

Place the variable declaration in if The scope of the variable will be limited in the condition of the statement , But this value is implicitly converted to a Boolean value , Therefore, it may not be clear which Boolean attribute to test .

The intent of the following code is clearer :

absl::optional<bool> b = MaybeBool();
if (b.has_value()) {
     ... }

Please note that , actually , The code snippet above is equivalent :absl::optional To bool Only view optional Whether is full , Instead of looking at its contents . Readers may find that optional(false) by true Contrary to common sense , But it's clear optional(false) There is a value . Again , When the underlying type can be implicitly converted to bool when , You need to be extra careful .

One mode of optional return values is to place variable declarations in if In the condition of the statement . This limits the range of variables , But it involves implicit conversion of Booleans :

if (absl::optional<Foo> foo = MaybeFoo()) {
    
  DoSomething(*foo);
}

Be careful : stay C++17 in ,if Statements can contain initializers , Therefore, the scope of the declaration can be limited , While avoiding implicit conversions :

if (absl::optional<Foo> foo = MaybeFoo(); foo.has_value()) {
    
  DoSomething(*foo);
}

Boolean like enumeration

Suppose you have adopted the technique #94 The advice of , And decided to use enumeration instead of bool, In order to get better readability at the calling site . This refactoring may introduce implicit transformations into function definitions :

void ParseCommandLineFlags(
    const char* usage, int* argc, char*** argv,
    StripFlagsMode strip_flags_mode) {
    
  if (strip_flags_mode) {
      //  Which value is true ?
    ...
  }
}

You can get extra clarity by replacing implicit conversion with explicit comparison :

void ParseCommandLineFlags(
    const char* usage, int* argc, char*** argv,
    StripFlagsMode strip_flags_mode) {
    
  if (strip_flags_mode == kPreserveFlags) {
    
    ...
  }
}

summary

All in all , Pay attention to the transformation from concealment to bool It may not be clear , So consider writing more explicit code :

  • Match the pointer type with nullptr Compare ( Especially if the type pointed to can be implicitly converted to bool).
  • Use things like absl::optional::has_value() Boolean functions like test whether the container is empty ( Especially if the contained type can be implicitly converted to bool). Yes if Use an optional initialization form to limit the range of variables ( Tips #165). But remember to call only the interface , Don't get value() or has_value() The address of . testing::Optional Matchers can help test .
  • Compare an enumeration with a specific value .
    Refer to :Contextual conversions
原网站

版权声明
本文为[-Flying crane-]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207071522591098.html