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

记一次因对象构造顺序引发的踩内存问题

记一次因对象构造顺序引发的踩内存问题

背景与现象

template<typename T>
struct range_reader
{range_reader(const T &low_bound, const T &upper_bound): low_(low_bound), high_(upper_bound){}T operator()(const std::string &s){T ret = default_reader<T>()(s);if (!(ret >= low_ && ret <= high_))throw cmdline::cmdline_error(s + " out of range" + constraint());return ret;}const std::string &constraint(){msg_.clear(); // ERROR 这里崩溃msg_ = "[" + detail::lexical_cast<std::string>(low_) + ", " + detail::lexical_cast<std::string>(high_) + "]";return msg_;}private:const T low_, high_;std::string msg_;
};

如上述代码,代码中存在调用 range_reader<T>::constraint() 方法的地方。有一处对该方法的调用必然在第一次访问 msg_ 对象时引发崩溃,且根据崩溃信息确认错误是踩内存。

分析与解决

已经确认是踩内存,因此首先断点打到 msg_.clear() 这行,观察栈帧中的变量。发现无法读取 msg_ ,且同生命周期的 low_high_ 的值都是未定义的,说明当前的 range_reader 对象没有被初始化。

于是顺着栈帧网上找,发现调用 range_reader<T>::constraint() 方法是在这里:

template<typename T, typename R>
class option_with_value_with_reader : public option_with_value<T>
{
public:option_with_value_with_reader(const std::string &full_name, char short_name, const class description &desc,bool required, const T default_value,R value_reader): option_with_value<T>(full_name, short_name, full_description(desc), required, default_value), reader_(value_reader){}//...
private:class description full_description(const class description &desc){// NOTE 这里不能调用reader_,因为reader_尚未被初始化(该函数在构造函数中被调用)return cmdline::description(desc.brief() + " " + reader_.constraint(), desc.detail());}//...R reader_;
};

option_with_value_with_reader 的构造函数中调用了 full_description() ,其中又调用了 range_reader<T>::constraint() 。而在 option_with_value_with_reader 的初始化列表中,reader_ 的初始化放在了调用 full_description() 之后——即调用 full_description()reader_ 对象尚未初始化。

由于继承关系中的构造函数调用顺序始终是先调用基类的构造函数再调用子类的,所以这里无法通过调整初始化列表中的顺序来解决。最终的解决方案是调整代码逻辑,不要在构造函数的初始化列表中使用当前类的直接成员(即使是基类继承而来的成员),而是改为在构造函数体中调用 full_description() 函数。

http://www.jsqmd.com/news/13730/

相关文章:

  • 恒流电路的震荡问题
  • 六维力传感器材质选择:影响性能与精度的关键因素 - 实践
  • CSharp: Aspose.CAD 25.10 Convert DWG and DXF to PDF
  • vtk学习——Pipeline
  • 长沙四大名校x东方project
  • Rust 的英文数字验证码识别系统设计与实现
  • IOS开发 - UIViewController 界面控制基类解析
  • SpringBoot运维实用篇(YW-1.SpringBoot程序的打包与运行,YW-2.配置高级,YW-3.多环境开发,YW-4.日志) - a
  • CSP-S模拟31
  • matlab 2025b + adalm-pluto 链接测试
  • Fortran 实现英文数字验证码识别系统
  • 10.14 NOIP 模拟赛 T1. HappyLovelyEveryday!
  • P3111 [USACO14DEC] Cow Jog S 题解 - 符星珞
  • Patch_SCN for Linux 功能完善---惜分飞
  • SQL在智能自动化业务场景中的应用 - Irving11
  • 20251014 杂题
  • 完整教程:Android Framework默认给应用添加dangerous级别权限
  • 20251013 模拟赛 总结
  • 高级语言作业第一次随笔
  • .net Core资料
  • 吾の歌单
  • 什么是反应式编程 - 详解
  • SDL3和其附属的编译记录
  • Qwen多模态系列模型笔记—Qwen2-VL
  • k8s Service Nodeport 用于集群外部访问
  • WPF 调用 ChangeWindowMessageFilterEx 修改指定窗口 (UIPI) 消息筛选器的用户界面特权隔离
  • 机器学习比赛
  • 牙科诊所借力AI营销4个月创收13万
  • 10月14日日记
  • P4653 [CEOI 2017] Sure Bet