自动和代理对象

有时 auto 的行为可能与程序员的预期不同。它类型推断表达式,即使类型推导不是正确的事情。

例如,在代码中使用代理对象时:

std::vector<bool> flags{true, true, false};
auto flag = flags[0];
flags.push_back(true);

这里 flag 不是 bool,而是 std::vector<bool>::reference,因为对于 bool 模板 vector 的特化,operator [] 返回一个代理对象,其中定义了转换运算符 operator bool

flags.push_back(true) 修改容器时,这个伪引用可能最终悬空,指的是一个不再存在的元素。

它还使下一种情况成为可能:

void foo(bool b);

std::vector<bool> getFlags();

auto flag = getFlags()[5];
foo(flag);

vector 立即被丢弃,因此 flag 是对已被丢弃的元素的伪引用。对 foo 的调用会调用未定义的行为。

在这种情况下,你可以使用 auto 声明一个变量,并通过强制转换为你想要推断的类型来初始化它:

auto flag = static_cast<bool>(getFlags()[5]);

但在那时,简单地用 bool 取代 auto 更有意义。

代理对象可能导致问题的另一种情况是表达式模板 。在这种情况下,为了提高效率,模板有时不会设计为超出当前的完整表达式,并且在下一个上使用代理对象会导致未定义的行为。