auto 和 static_casts - 好的做法

auto and static_casts - good practice

在 Scott Meyer 的 Effective Modern C++ 一书中,我们可以读到:

std::vector<bool> features(const Widget& w);
Widget w;
…
bool highPriority = features(w)[5];
…
processWidget(w, highPriority); 

和自动选项

auto highPriority = features(w)[5];

这会导致未定义的行为,因为 features() 是 returning std::vector<bool>,当 [=35= 时使用 std::vector<bool>::reference 类型的代理对象] 从 opearator[].

中获取一个值

作为解决方案,建议不要停止使用 auto,而是使用 static_casts.

Scott Meyers 建议使用:

auto highPriority = static_cast<bool>(features(w)[5]);

而不是:

bool highPriority = features(w)[5];

我的问题是: 这两者之间的真正区别是什么?在我看来,两者都是一样的,因为这两种方法都以完全相同的方式使重构变得更加困难(在函数特性中更改 return 值类型不会使变量 highPriority 成为不同的类型),而第二种方法编写起来更短。

features一个函数returns一个std::vector<bool>,

auto highPriority = features(w)[5];

存储逻辑引用。存储的对象引用了一个不再存在的向量。使用它会导致未定义的行为。

改为

bool const highPriority = features(w)[5];

auto const highPriority = !!features(w)[5];

或者,正如 Scott 所建议的那样——但对我来说太冗长了——使用 static_cast.

存储的对象现在是 bool

这三种表达相同声明的方式在功能上没有区别。唯一的区别是非功能性的:在我看来 static_cast 不必要的冗长,以及 !! 可能会抑制来自一个常见编译器的关于性能的愚蠢警告。

如果你不喜欢features的界面,你可以在辅助函数中隐藏丑陋

bool is_high_priority(const Widget& w)
{ return features(w)[5]; }

现在你的

auto highPriority = is_high_priority(w);

按预期工作。

当您使用 auto 时,auto 将其推断为由 highPriority 编辑的 return 类型,highPriority 是对 bool 的引用。问题是,highPriority 不是 return 对 bool 的引用,而是 std::vector::reference 对象。 ('reference' 是 std::vector 内的嵌套 class)。 std::vector::reference 是一个 "proxy class",一个模拟其他类型行为的 class。它不仅是代理 class,而且是 "invisible" 代理 class。这样的 classes 不适用于自动。 Auto 无法正确推断出不可见代理的类型 class。但是 static_cast 强制将高优先级转换为 bool。这避免了未定义的行为。