应使用const引用传递避免临时对象构造,预分配vector内存减少重分配,优先利用移动语义替代拷贝,循环外提取重复计算,字符串比较用string_view或const char*。

用 const 引用代替值传递参数
循环中频繁构造临时对象,常源于函数调用时把对象按值传入。比如 std::vector<std::string> 遍历时写成 for (auto s : vec),每次迭代都复制一个 std::string ——尤其字符串内容长时开销明显。
改用 const auto& 直接绑定原对象,避免拷贝构造:
for (const auto& s : vec) { // 不触发 string 拷贝
process(s);
}- 若需修改副本,再显式写
auto s = item,明确意图 - 对 POD 类型(如
int、double),引用反而可能略慢,但编译器通常会优化掉;不必为这点微小差异牺牲可读性 - 注意:不能对右值(如临时对象)取非常量引用,
const auto&可绑定右值,但auto&不行
reserve() 预分配 vector 内存
循环中反复 push_back() 容易触发多次内存重分配 + 元素逐个拷贝(或移动),尤其是存储非 trivial 类型时。这不是“每次迭代复制对象”,而是“因容量不足被迫批量复制”。
提前知道大致数量?直接 reserve():
立即学习“C++免费学习笔记(深入)”;
std::vector<HeavyObject> results;
results.reserve(expected_count); // 一次性分配足够内存
for (const auto& x : input) {
results.push_back(compute(x)); // 不再触发 realloc + copy
}-
reserve()只影响 capacity,不改变 size,也不调用元素构造函数 - 如果完全不确定大小,至少用
reserve(16)或类似小值兜底,减少早期频繁扩容 - 注意:
resize()会构造默认对象,不是替代方案
移动语义替代拷贝(C++11 起)
当必须生成新对象(如工厂函数返回、容器插入),优先让类型支持移动构造/赋值。否则即使写了 std::move(),也会退化为拷贝。
检查类是否满足“可移动”条件:
- 没有用户定义的拷贝构造/拷贝赋值(或它们是 defaulted)
- 有 noexcept 的移动构造/移动赋值(推荐显式加
noexcept) - 成员变量本身也支持移动(如
std::string、std::vector默认支持)
循环中使用示例:
std::vector<BigBuffer> buffers;
for (int i = 0; i < n; ++i) {
buffers.push_back(create_buffer(i)); // create_buffer 返回 BigBuffer&&
// 编译器自动选择移动构造,而非拷贝
}若你控制不了 create_buffer 的返回类型,至少确保接收端不强制拷贝:push_back(std::move(temp)) 是安全的,但别对 const 对象或函数返回值重复 move —— 编译器已处理好。
避免在循环条件里重复计算或隐式转换
看似不相关,但常导致意外拷贝:比如 for (size_t i = 0; i < obj.get_data().size(); ++i),每次迭代都调用 get_data()(返回 std::vector 副本)再取 size()。
更糟的是带隐式转换的比较:
// 错误:每次循环都构造 std::string 临时对象
for (const auto& item : items) {
if (item.name == "target") { ... } // item.name 是 const char*
}- 把
obj.get_data().size()提到循环外,或改用范围 for - 字符串字面量比较尽量用
std::string_view(C++17)或直接比const char*,避免构造std::string - 自定义类型重载
operator==时,参数用const T&,别用值传参
真正关键的不是“少写几行”,而是每次迭代前,问一句:这个表达式有没有悄悄 new 一个对象出来?


















