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