我正在使用Bison&弯曲1个月或多或少,所以我很抱歉,如果我没有看到明显的东西(但我认为不是这样)。
我有一个关于使用Flex Bison释放内存的问题。这是我的代码:
parser.l
{DATE} { yylval.str= strdup(yytext);
pair<string,string> newpair = make_pair("DATE",yytext);
myvector.push_back(newpair);
return TOKEN_DATE ;}
这是我的.l文件的示例之一。我将yytext的值复制到yylval.str中。然后我创建一个具有该内容的新对(实际上是键/值),然后我返回bison的令牌日期。 我的解析器.y不超过yyparse;当抓到东西时,它就会打印出来。
我尝试在此运行valgrind,我有关于strdup的多个错误。我知道这个函数使用malloc,但我不知道WHERE和WHEN使用FREE。
我可能猜到它在.y文件中,但在哪里?
test:
TOKEN_DATE { cout << $1 << endl; // here ? and what to free ?}
我并不是真的得到了所有这些,我真的很感激一个简单明了的解释。
提前致谢,
编辑:
我尝试了几件事:
test:
TOKEN_DATE TOKEN_TOTO TOKEN_BLABLA { cout << $1 << endl; free($1); free($2);}
| TOKEN_DATE test { cout << $1 << endl, free($1); }
似乎编译和执行良好,但valgrind仍然告诉我strdup函数中包含的malloc存在问题。但我不能在flex文件中写自由(yylval.str),否则,野牛不会意识到这个值(如果我理解正确的话,我试过它并不起作用)。我真的不知道如何消除这个泄漏的问题。
答案 0 :(得分:5)
一旦不再需要,您需要释放复制的字符串。在你相当简单的情况下,你可以在打印之后释放($ 1),但通常情况是解析器将复制的字符串插入到某个数据结构中,在这种情况下,数据结构成为malloc存储的所有者,并且免费电话将在析构函数中执行。
与任何其他资源管理问题没有什么不同;您需要始终清楚谁是已分配资源的所有者,因为所有者有责任在不再需要时释放资源。
内部发生的是bison
维护一堆语义值,每个语义值都有YYSTYPE
类型(即“语义类型”),这也是{{1}的类型}。当令牌移到堆栈上时,yylval
将bison
复制到堆栈顶部。在执行与生产相对应的操作之前,yylval
安排生产中每个终端和非终端的语义值被称为bison
,$1
等(这是不是副本;各种$2
符号将替换为对$x
堆栈上的位置的引用。)
非终端也具有语义值,因为每个动作都将值存储到伪变量bison
中。 (如果操作不执行此操作,则$$
的值无法预测,但仍然存在。)操作完成后,bison将删除$$
,$1
...值从堆栈顶部开始,然后将伪变量$2
复制到堆栈顶部。它对弹出的值没有任何作用,因此如果它们需要被释放或以其他方式被破坏,动作必须自己执行此操作。
由于语义值是天真地复制的,因此语义类型不应包含任何不易复制的C ++对象。
如果使用$$
声明,则语义类型%union
是YYSTYPE
对象,您需要告诉union
哪个联合标记适用于每个终端,非末端。在这种情况下,bison
和所有$$
都会自动附加正确的$n
,这些操作会更加类型安全。
答案 1 :(得分:2)
来自flex手册:
21.3关于yytext和记忆的注释
当flex找到匹配项时,yytext指向的第一个字符 在输入缓冲区中匹配。字符串本身是输入的一部分 缓冲区,不单独分配。 yytext的值将是 下次调用yylex()时会覆盖。总之,价值 yytext仅在匹配规则的操作中有效。
因此,不应该将make_pair作为以下内容吗?
pair<string,string> newpair = make_pair("DATE",yylval.str);
如果是这样,那么在清理对内存时应该释放字符串。
答案 2 :(得分:1)
答案很简单:这取决于。无论何时,只要可能,你就应该释放内存。
更有帮助的答案:尝试使用尽可能少的内存分配。如果你永远不会malloc
任何记忆,你永远不必free
任何记忆。在您给出的示例中,您在日期上进行模式匹配。通常日期保持格式并且具有一些上限;例如,格式'yyyy / mm / dd'中有10个字符。如果你可以期待这一点,你可以简单地将一个静态大小的字符数组放到yylval
中,而不是创建一个新的字符串来保存日期,例如char date[10];
。