85 / 103 · C++11 · 约 11 分钟
auto 不等于引用:检查复制和别名的边界
auto 推导的是声明所需的类型,不会自动保留初始化表达式的引用属性。对比容器复制、引用别名和数组退化,再用类型断言固定意图,避免把“省略类型名”误当成“省掉复制”。
Overview of the New C++ (C++11/14)
已完整读完Artima官方42页样张(标题/版权2页,Slides1—40),包括导论、复制移动概览、词频程序C++98/11对照、auto、range-for、nullptr、枚举、Unicode与原始字符串。统一初始化、decltype等仅在课程目录或说明中出现,不计实读;完整409页课程其余内容未取得、未读。
查看版本、实际阅读范围与原文入口 →看声明形式,不只看等号右侧
给定一个 const 容器,auto snapshot = source 通常创建一个新的非 const 容器;const auto& view = source 才绑定到原对象。顶层 const 和引用信息是否保留,取决于左侧有没有相应的声明修饰,不能仅看右侧是不是引用。
示例故意使用可修改的原始容器:复制后修改 snapshot,原值不变;通过 auto& 得到的 alias 修改则影响原值。这两个断言回答“操作作用于谁”,比笼统地说 auto 更现代更有用。const 引用限制这个访问路径,但不冻结所有其他别名。
数组退化是一处能静态看见的差异
把数组用 auto p = array 初始化,得到指针,长度不在 p 的类型里;写 auto& whole = array 则保留数组引用。用 is_same 和 static_assert 直接验证两者,避免靠 sizeof 恰好相同的机器结果猜测类型。
类型检查和行为检查互补:静态断言说明接口性质,运行时断言说明别名访问能改到同一个元素。这些规则不是 auto 私有的魔法,它们与模板参数推导密切相关;课程样张正是用这种联系来解释简洁语法背后的成本和约束。
把历史语法说明放在版本里
已读样张修订于2015年,覆盖课程开头到原始字符串,不等于读过整份训练材料。它的 auto 讨论适合建立基础,但遇到花括号初始化、返回类型推导等细节,还必须查看相应语言版本及后续缺陷修正。
本例刻意不依赖有争议的历史花括号推导写法,最低要求 C++11,在 C++20 仍成立。对于长期保存的引用还要另查源对象寿命:auto& 不会替你延长普通左值对象的寿命,也不会阻止容器扩容使元素引用失效。
容易答错的地方
- auto by-value 可以复制整个容器;类型名变短不代表程序更少分配。
- const auto& 不是所有权;原对象销毁或引用目标失效后,别名仍会悬空。
运行一个例子
最低标准 C++11 · 完整程序 · 下载 .cpp
#include <cassert>
#include <type_traits>
#include <vector>
int main() {
std::vector<int> source{2, 4};
auto snapshot = source;
auto& alias = source;
const auto& view = source;
snapshot[0] = 9;
assert(source[0] == 2 && snapshot[0] == 9);
alias[1] = 7;
assert(source[1] == 7 && view[1] == 7);
static_assert(std::is_same<decltype(snapshot), std::vector<int>>::value, "value copy");
static_assert(std::is_same<decltype(view), const std::vector<int>&>::value, "const alias");
int samples[3] = {1, 2, 3};
auto pointer = samples;
auto& whole = samples;
static_assert(std::is_same<decltype(pointer), int*>::value, "array decays");
static_assert(std::is_same<decltype(whole), int (&)[3]>::value, "bound retained");
whole[2] = 8;
assert(pointer[2] == 8 && samples[2] == 8);
}
在本地编译
g++ -std=c++11 -Wall -Wextra -Wpedantic -pthread books-overview-new-cpp.cpp -o example && ./example预期结果
预期:正常退出、无输出;所有 assert 通过。
CHECK YOUR UNDERSTANDING
合上答案,试着解释。
把 source 改成 const vector,auto snapshot 与 auto& alias 分别是什么类型?
查看参考答案
snapshot 仍是 std::vector<int>,因为 by-value 推导去掉初始化类型的顶层 const;alias 则是 const std::vector<int>&,因为引用推导保留被引用对象的 const。所以 snapshot[0] 可写,而 alias[0] 不可写。可将运行时改写 alias 的语句删除,新增两条 is_same 静态断言验证这两个类型。
继续查证
标准草案链接会随工作草案更新;本文版本标记对应示例最低要求,不表示草案中的所有新规则都适用于旧标准。