SDL中文论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 4973|回复: 1
打印 上一主题 下一主题

[WML/lua] preprocessor_data::get_chunk中的一段代码是否可能导致内存泄漏?

[复制链接]

21

主题

36

帖子

334

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
334
跳转到指定楼层
楼主
发表于 2020-8-24 16:41:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. std::ostringstream res;
  2. preprocessor_streambuf *buf = new preprocessor_streambuf(target_);
  3. {
  4. std::istream in(buf);
  5. new preprocessor_data(*buf, called_macros_, buffer, val.location, "", val.linenum, dir, val.textdomain, &symbol);
  6. res << in.rdbuf();
  7. }
  8. delete buf;
  9. strings_.back() += res.str();
复制代码
代码功能上是实现宏扩展,简单上说是宏替换。symbol:宏名;buffer:宏内容。例如有这样一个宏:
#define GUI_TINY__RESOLUTION
window_width = 640
window_height = 480
#enddef
则symbol内容是“GUI_TINY__RESOLUTION”,buffer内容是“\twindow_width = 640\r\n\twindow_height = 480\r\n”。但要注意,symbol类型是std::string,buffer则是一个指向std::stringstream类型的指针。

要讨论是否可能导致内存泄漏,要确定有哪些变量可能导致泄漏,集中看一条语句:
  1. new preprocessor_data(*buf, called_macros_, buffer, val.location, "", val.linenum, dir, val.textdomain, &symbol);
复制代码
这是从堆中分配preprocessor_data,这条语句有三处是从堆中分配的。

一、preprocessor_data对象。new preprocessor_data(...)。

二、buf,preprocessor_streambuf对象。buf = new preprocessor_streambuf(target_);

三、buffer,std::stringstream对象。这分配过程没有在这部分,参考原代码,语句是std::stringstream *buffer = new std::stringstream。

答案是这段代码不会导致内存泄漏。现在看它们是在何时、如何被释放。
回复

使用道具 举报

21

主题

36

帖子

334

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
334
沙发
 楼主| 发表于 2020-8-24 16:41:32 | 只看该作者
一:preprocessor_data对象
此处用一个没有条件的{},它的作是限定in这个对像的的作用域,以便退出这个作用域时in的析构函数可以自动被调用。但是,当in的析构函数被调用时构,它至少是不会释放掉以上三个指针中的任何一个。
        

释放preprocessor_data对象指针既不在in析构也不是在delete buf时候,是在res << in.rdbuf()执行过程中!in对象在构造时也使用preprocess_streambuf数据读取机制,即使用underflow被重载的机制,致使上res << in.rdbuf()会调用preprocess_streambuf::underflow,进而调用preprocess_data::get_chunk,而在in.rdbuf()数据被全部导出到内存之后(还没有放在res,参考get_chunk代码),那里的delete current_被起作用,把preprocessor_data对象给释放了!

二:buffer
buffer呢,buffer在哪里被释放了?——buffer也是在res << in.rdbuf()执行过程中被释放,也是在delete current_时候。因为preprocessor_data有一个类成员变量:in_,当reprocessor_data析构被调用时,这个作为成员的类,它的析构函数自动被调用。

scoped_istream in_定义了in_是preprocessor_data的一个成员。preprocessor_data构造函数时对in_初始化是执行in_(i),具体到此处i值就是buffer!结合scoped_istream类代码,scoped_istream的内部变量stream被赋了buffer的值,注意:这里是指针赋值,也就是说让stream也指向了buffer的内存区,在要释放内存区上这目的上,调用delete stream和delete buffer,buffer是等价的。——而正如我们预见的,scoped_istream的析构函数几乎就被猜出来了:
scoped_istream::~scoped_istream()
{
delete stream;
}

三:buf
代码一眼就能看到buf何时被释放,对buf释放问题难的可能是较容易让人产生误解,就像我,我也直觉认为in的析构会把buf给释放掉!毕竟in“雇佣”了buf。

std::istream析构时候,它不会释放“雇佣”的std::streambuf!调用程序要手动释放。

buf类型是preprocessor_streambuf,它的基类是streambuf,in是std::istream,std::istream in(buf)定义了一个从streambuf构造的std_istream。istream“雇佣”了一个streambuf,把streambuf作为它的一个成员变量,rdbuf方法就是向外暴露这个变量指针。这里若buf值是0x02de4440,则in.rdbuf()值就是0x02de4440。它们两人关系:

                         使用
istream/basic_istream =======> streambuf/basic_streambuf
                                    <======
                                      被使用

buf基类是basic_streambuf,它虽然被istream使用,但即使istream,即in,被析构了它不会被释放,代码要显示调用一个delete buf。

-----------------------------------------
小结:

解析*.cfg文件时,一旦使用preprocess_streambuf::underflow机制,当源(可能是文件:std::ifstream,可能是字符流:std::stringstream。只要它是从std::istream派生就行)被读空后,它会自动释放掉两处资源:preprocessor_data自己,源指向的块。正因为这种preprocessor_data能释放自已,wesnoth代码中对new preprocessor_data出来的值是不赋给其它变量,因为它自释放。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|丽谷软件|libsdl.cn

GMT+8, 2025-5-2 03:30 , Processed in 0.080940 second(s), 19 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表