当前位置: 首页 > 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.hskmm.com/?act=detail&tid=31195

相关文章:

  • 恒流电路的震荡问题
  • 六维力传感器材质选择:影响性能与精度的关键因素 - 实践
  • C尖笔记
  • 浅谈自学习编程以来学到的代码规范
  • Jenkins Share Library教程 —— 高级实战与最佳实践教程
  • qoj.6555 Sets May be Good 做题记录
  • 结构化数据自动生成文本技术解析
  • 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
  • Fortran 实现英文数字验证码识别系统
  • 10.14 NOIP 模拟赛 T1. HappyLovelyEveryday!
  • CSP-J 2025 入门级模拟赛 Day6 复盘 B. 罐の水表
  • 10.14每日总结
  • 四边形不等式
  • 20251014 杂题
  • 二叉树的遍历
  • SQL在智能自动化业务场景中的应用 - Irving11
  • 拼接字符串要求字典序最小
  • 高级语言作业第一次随笔
  • C#实现开机自启动应用多种方式
  • 日志|二叉树|110平衡二叉树|111二叉树的最大深度|199二叉树的右视图
  • Chrome在Speedometer 3.1创下历史最高分,为用户节省数百万小时
  • 西电CTF平台——Moectf 2025 WriteUP
  • [笔记]并查集进阶(带权、扩展域、带删除)
  • 20251013 模拟赛 总结