当前位置: 首页 > news >正文

Effective C++ 条款26: 尽可能延后变量定义式的出现时间

Effective C++ 条款26:尽可能延后变量定义式的出现时间


核心思想将变量定义推迟到真正需要使用它的时刻,并在定义时直接初始化,避免不必要的构造函数/析构函数调用开销,提升程序效率与资源利用率。

⚠️ 1. 过早定义的性能代价

不必要的构造/析构开销

std::string encryptPassword(const std::string& password) {using namespace std;string encrypted;  // 过早定义(此时尚未使用)if (password.length() < MinimumLength) {throw logic_error("Password too short");}encrypted = password;         // 赋值操作encrypt(encrypted);           // 加密处理return encrypted;
}

性能分析

  1. 即使抛出异常 → encrypted仍被构造和析构
  2. 先默认构造 + 再赋值 → 效率低于直接构造

循环中的性能陷阱

// 方式A:循环外定义
Widget w;
for (int i = 0; i < n; ++i) {w = getWidget(i);  // 赋值操作process(w);
}  // 1次构造 + n次赋值 + 1次析构// 方式B:循环内定义
for (int i = 0; i < n; ++i) {Widget w = getWidget(i);  // 构造操作process(w);
}  // n次构造 + n次析构

🚨 2. 解决方案:延后定义+直接初始化

安全高效实现

std::string encryptPassword(const std::string& password) {if (password.length() < MinimumLength) {throw logic_error("Password too short");}// 延后定义 + 直接初始化std::string encrypted = password;  // 拷贝构造encrypt(encrypted);                // 修改对象return encrypted;
}  // 仅1次构造+1次析构

循环场景优化

// 情况1:赋值成本 < 构造+析构成本 → 循环外定义
Widget w;
for (int i = 0; i < n; ++i) {w = getWidget(i);  // 高效赋值process(w);
}// 情况2:赋值成本高 → 循环内定义
for (int i = 0; i < n; ++i) {Widget w(getWidget(i));  // 移动构造/直接初始化process(w);
}// 情况3:支持移动语义 → 循环内定义更优
for (int i = 0; i < n; ++i) {auto w = createWidget(i);  // 直接构造process(std::move(w));
}

⚖️ 3. 关键原则与性能权衡
定义策略适用场景性能特点
延后定义+初始化函数局部变量避免不必要的构造/析构
循环外定义赋值成本低 + 构造成本高1构造 + n赋值 + 1析构
循环内定义赋值成本高 + 构造成本低n构造 + n析构
移动语义定义类型支持高效移动(C++11+)n移动构造 + n析构

现代C++优化技巧

// 场景1:条件初始化
auto value = [&] {if (condition) return computeValueA();else return computeValueB();
}();  // IIFE立即调用函数表达式// 场景2:复杂初始化
auto config = [&] {Config cfg;cfg.loadDefaults();if (userOverride) cfg.merge(userConfig);return cfg;
}();// 场景3:结构化绑定(C++17)
auto [min, max] = findMinMax(data);

资源获取即初始化(RAII)

// 文件处理:定义即初始化
{std::ofstream logFile("debug.log");  // 获取资源logFile << "Start processing\n";     // 使用资源
}  // 自动释放资源// 锁管理:作用域控制
void criticalSection() {std::lock_guard<std::mutex> lock(mtx);  // 延后到需要时定义modifySharedData();
}  // 自动释放锁

💡 关键原则总结

  1. 定义即使用原则
    • 变量定义点应紧邻首次使用点
    • 避免在控制流分支前定义变量
  2. 直接初始化优先
    • 使用拷贝构造而非默认构造+赋值
    • 利用移动语义减少拷贝开销
  3. 循环场景权衡
    • 比较赋值成本 vs 构造+析构成本
    • 移动语义改变传统权衡标准
  4. 作用域最小化
    • 将变量限制在最小必要作用域
    • 增强代码可读性和安全性

错误模式重现

void processData(const Data& input) {Logger log;  // 过早定义(可能不使用)Validator validator;  // 构造开销大if (!input.isValid()) return;  // 提前返回 → 不必要的构造/析构log.write("Start processing");validator.check(input);// ...
}

安全重构方案

void processData(const Data& input) {if (!input.isValid()) return;  // 提前返回无开销// 延后定义Logger log("process.log");  // 定义即使用log.write("Start processing");Validator validator(input);  // 直接初始化validator.check();// 现代C++:仅在需要时获取资源auto dbConnection = [&] {if (needDB) return openDatabase();return DatabaseConnection(nullptr);}();
}// 循环优化示例
void batchProcess(const std::vector<Request>& requests) {// 情况:Widget移动成本低 → 循环内定义for (const auto& req : requests) {Widget w = createWidget(req);  // 移动构造w.process();}// 情况:Validator复用成本低 → 循环外定义Validator validator;for (const auto& req : requests) {validator.reset();validator.validate(req);}
}
http://www.dtcms.com/a/318540.html

相关文章:

  • 007 前端( JavaScript HTML DOM+Echarts)
  • 【保留小数精度不舍入】2022-10-8
  • MaxKB 使用 MCP 连接 Oracle (免安装 cx_Oracle 和 Oracle Instant Client)
  • 智慧水务管理系统
  • C++、STL面试题总结(二)
  • 三、Envoy的管理接口
  • 数据科学与计算pandas
  • 沉寂半年,Kimi归来!
  • 地铁和城市宏基因组项目metaSUB
  • 脂质体转染、物理转染(电穿孔)与病毒转染:原理及操作步骤详解
  • nlp-词汇分析
  • 【Dify学习笔记】:Dify搭建表单信息提交系统
  • windows系统创建ubuntu系统
  • C++线程中 detach() 和 join() 的区别
  • hf的国内平替hf-mirror
  • AT32的freertos下modbus TCP移植
  • cdn是什么
  • 快手小店客服自动化回复
  • 记一次连接池泄漏导致的线上事故排查与修复
  • 从基础功能到自主决策, Agent 开发进阶路怎么走
  • 赋能智能制造,向成电子XC3576H/XC3588H工业主板引领AI工控新时代
  • 什么是RabbitMQ?
  • 基于单片机GD32E103的HID按键问题分析
  • 【网络运维】Linux:SELinux简介和配置
  • STM32U5 外部中断不响应问题分析
  • 【android bluetooth 协议分析 03】【蓝牙扫描详解 4】【BR/EDR扫描到设备后如何上报给app侧】
  • PHP 继承与静态机制深度解析
  • 防御保护综合练习
  • 北斗变形监测技术应用解析
  • HTTP Flood攻击:数字时代的“蝗虫灾害“与智能防护之道