C++ std::Bison中的共享\u ptr导致成员错误
我试图通过使用std::shared\u ptr使bison的内存效率更高。我不想使用原始指针。我使用一个节点系统作为解析树,所以我将YYTYPE定义为std::shared_ptr。在使用一些简单的语法运行它之后,我得到了编译错误: C2039“块节点”:不是“std::shared\u ptr”的成员 <> p>我发现这很奇怪,因为C++中运行的等效代码工作得很好, std::shared_ptr test=std::make_shared 我错过了什么 需要C++ std::Bison中的共享\u ptr导致成员错误,c++,bison,smart-pointers,flex-lexer,C++,Bison,Smart Pointers,Flex Lexer,我试图通过使用std::shared\u ptr使bison的内存效率更高。我不想使用原始指针。我使用一个节点系统作为解析树,所以我将YYTYPE定义为std::shared_ptr。在使用一些简单的语法运行它之后,我得到了编译错误: C2039“块节点”:不是“std::shared\u ptr”的成员 p>我发现这很奇怪,因为C++中运行的等效代码工作得很好, std::shared_ptr test=std::make_shared 我错过了什么 需要 %code requires {
%code requires {
typedef void* yyscan_t;
#include "node.h"
#include <memory>
#define YYSTYPE std::shared_ptr<Node>
}
联合
文法
%start program
%%
program : input { *result = $1; } // <- error here
;
input: '\n' { $$ = std::make_shared<BlockNode>();} // <- error here
;
%%
Node.h
class Node /*: public std::enable_shared_from_this<Node>*/ {
public:
std::string myString;
Node() {}
~Node() { std::cout << "destoryed" << myString << std::endl; }
};
class BlockNode : public Node {
public:
BlockNode() {
myString = "block node";
std::cout << "created" << myString << std::endl;
}
};
你应该知道的第一件事是这个设计不能工作。如果您为bison使用默认的C API,则不能使用不可复制的语义类型,因为如果需要重新分配堆栈,bison将按字节复制它的堆栈,我相信还有其他问题与在不调用析构函数的情况下覆盖字节有关。如果你想使用共享指针,你应该研究如何使用C++ API,我认为它已经达到某种程度的成熟,虽然我还没有使用它。你可能会对结果更满意 不管怎样,您的代码还有一些其他问题 首先,现代bison应用程序不应该定义YYSTYPE,甚至不应该在%代码块中定义。你应该改用
%define api.value.type { /* SemanticType */ }
如果您这样做了,bison会告诉您不能同时使用%union声明和固定的api.value.type。如果语义类型是并集,那么它就是并集。它也不能是共享的\u指针。既然您似乎希望它是一个成员都是共享指针的联合体,那么它就是一个联合体,您不希望以其他方式定义它
如果您使用define YYSTYPE,并且还使用了%union,那么您将发现%union永远不会被应用union将YYSTYPE的默认定义插入为union YYSTYPE,但YYSTYPE的显式定义将覆盖该定义。但是bison不知道您已经这样做了-直到C编译器实际编译生成的代码才变得明显-因此它使用您在%类型声明中提供的标记重写语义值引用。换句话说,当您说%type input时,bison会通过添加字段引用自动将引用输入非终端实例的任何引用更改为$n,就像您编写了$n.blockNode一样,当然,您不能这样做,因为bison已经添加了字段引用。但是,定义重写YySype不是一个联合,它是一个SyrdPyPosits,并且SydDyPosil没有块节点成员,正如C++编译器错误消息所指示的那样。
类似地,在输入规则中,%类型声明导致bison发出代码,该代码将分配给不存在的blockNode成员
为了说明我的第一点——您不能将shared_指针用作C代码生成器的语义类型或联合成员——我通过应用上面的建议修复了您的代码,即删除define YYSTYPE,并进行了或多或少的更改,以避免其他bison和编译器错误,导致以下错误:
文件tom.yy
你应该知道的第一件事是这个设计不能工作。如果您为bison使用默认的C API,则不能使用不可复制的语义类型,因为如果需要重新分配堆栈,bison将按字节复制它的堆栈,我相信还有其他问题与在不调用析构函数的情况下覆盖字节有关。如果你想使用共享指针,你应该研究如何使用C++ API,我认为它已经达到某种程度的成熟,虽然我还没有使用它。你可能会对结果更满意 不管怎样,您的代码还有一些其他问题 首先,现代bison应用程序不应该定义YYSTYPE,甚至不应该在%代码块中定义。你应该改用
%define api.value.type { /* SemanticType */ }
如果您这样做了,bison会告诉您不能同时使用%union声明和固定的api.value.type。如果语义类型是并集,那么它就是并集。它也不能是共享的\u指针。既然您似乎希望它是一个成员都是共享指针的联合体,那么它就是一个联合体,您不希望以其他方式定义它
如果您使用define YYSTYPE,并且还使用了%union,那么您将发现%union永远不会被应用union将YYSTYPE的默认定义插入为union YYSTYPE,但YYSTYPE的显式定义将覆盖该定义。但是bison不知道您已经这样做了-直到C编译器实际编译生成的代码才变得明显-因此它使用您在%类型声明中提供的标记重写语义值引用。换句话说,当您说%type input时,bison将通过添加字段引用自动将任何引用更改为$n,其中引用的是输入非终端的实例,就像您编写了$n.blockNode一样,当然,您不能这样做,因为
e bison已经添加了字段引用。但是,定义重写YySype不是一个联合,它是一个SyrdPyPosits,并且SydDyPosil没有块节点成员,正如C++编译器错误消息所指示的那样。
类似地,在输入规则中,%类型声明导致bison发出代码,该代码将分配给不存在的blockNode成员
为了说明我的第一点——您不能将shared_指针用作C代码生成器的语义类型或联合成员——我通过应用上面的建议修复了您的代码,即删除define YYSTYPE,并进行了或多或少的更改,以避免其他bison和编译器错误,导致以下错误:
文件tom.yy
这是C++中的联合的限制,一个联合的成员不能有构造函数。
union {
std::shared_ptr<BlockNode> blockNode; //not allowed
std::shared_ptr<Node> *testNode; //allowed
}
这是C++中的联合的限制,一个联合的成员不能有构造函数。
union {
std::shared_ptr<BlockNode> blockNode; //not allowed
std::shared_ptr<Node> *testNode; //allowed
}
我建议您查看生成的源,无论发生什么,都可能在那里完全清楚。需要注意的一点是,我不相信我曾经同时使用过重新定义的YYSTYPE和%union。我建议您查看生成的源代码,无论发生了什么,都可能在那里完全清楚。需要注意的一点是,我不相信我曾经同时使用过重新定义的YYSTYPE和%union。再次感谢您的伟大回答!是的,你所说的很有道理,我部分地遵循了我发现的一些非常古老的示例。因此,总结一下,我不能将%union与shared_ptr一起使用,因为它不是传统的语义类型,也不能将%define与shared_ptr一起使用,因为它没有成员,因此无法与派生节点类一起使用。也可以选择使用向下投射。在这种情况下,你认为管理记忆的最佳方法是什么?@Tom:这并不是说它不是一种传统的语义类型。这是因为C++不允许SyrdypTr成为联盟的成员。而且C++不允许与不具有可构造性的成员的默认构造。这和野牛没什么关系。您可以将%define与shared_ptr一起使用,但是您只能使用一种类型的共享指针no union来允许您使用多个指针,如果堆栈被重新分配,那么事情就会分崩离析;也就是说,数据类型在C中会有自己的感觉。如果你想释放C++超级大国,你需要使用C++ API。详见野牛手册。有很多细节。这是一个学习曲线,但是如果你觉得在C++中更自在,显然使用一个能生成真实C++的分析器生成器,而不是仅仅伪装成C++。野牛就是这样一个发电机,但你需要问你想要什么。你问我的个人意见,这是你在StackOverflow中必须小心的事情,在StackOverflow中,意见被认为是不允许的。但是,碰巧的是,我有一个。我会使用一个普通的C风格的指针,因为你正在构建一棵树,而一个共享的_指针将是巨大的过度使用。只要AST是一棵树,跟踪对象所有权就很简单。如果您以后想要执行公共子表达式消除或类似操作,那么您将需要一些其他内存管理机制。这可能涉及到共享指针。但是我,我会把这个留到以后,以防以后永远不会。再次感谢你的回答!是的,你所说的很有道理,我部分地遵循了我发现的一些非常古老的示例。因此,总结一下,我不能将%union与shared_ptr一起使用,因为它不是传统的语义类型,也不能将%define与shared_ptr一起使用,因为它没有成员,因此无法与派生节点类一起使用。也可以选择使用向下投射。在这种情况下,你认为管理记忆的最佳方法是什么?@Tom:这并不是说它不是一种传统的语义类型。这是因为C++不允许SyrdypTr成为联盟的成员。而且C++不允许与不具有可构造性的成员的默认构造。这和野牛没什么关系。您可以将%define与shared_ptr一起使用,但是您只能使用一种类型的共享指针no union来允许您使用多个指针,如果堆栈被重新分配,那么事情就会分崩离析;也就是说,数据类型在C中会有自己的感觉。如果你想释放C++超级大国,你需要使用C++ API。详见野牛手册。有很多细节。这是一个学习曲线,但是如果你觉得在C++中更自在,显然使用一个能生成真实C++的分析器生成器,而不是仅仅伪装成C++。野牛就是这样一个发电机,但你需要问你想要什么。你问我的个人意见,这是你必须小心的 我在StackOverflow里闲逛,那里不允许发表意见。但是,碰巧的是,我有一个。我会使用一个普通的C风格的指针,因为你正在构建一棵树,而一个共享的_指针将是巨大的过度使用。只要AST是一棵树,跟踪对象所有权就很简单。如果您以后想要执行公共子表达式消除或类似操作,那么您将需要一些其他内存管理机制。这可能涉及到共享指针。但是我,我会把它留到以后,以防以后永远不会。
$ bison -o tom.cc tom.yy
$ gcc -Wall -o tom tom.cc -ly
tom.cc:956:9: error: use of deleted function ‘YYSTYPE::YYSTYPE()’
YYSTYPE yylval;
^~~~~~
tom.cc:104:7: note: ‘YYSTYPE::YYSTYPE()’ is implicitly deleted because the default definition would be ill-formed:
union YYSTYPE
^~~~~~~
tom.yy:15:32: error: union member ‘YYSTYPE::blockNode’ with non-trivial ‘constexpr std::shared_ptr<_Tp>::shared_ptr() [with _Tp = BlockNode]’
std::shared_ptr<BlockNode> blockNode;
^~~~~~~~~
tom.yy:16:27: error: union member ‘YYSTYPE::testNode’ with non-trivial ‘constexpr std::shared_ptr<_Tp>::shared_ptr() [with _Tp = Node]’
std::shared_ptr<Node> testNode;
^~~~~~~~
tom.cc: In function ‘int yyparse()’:
tom.cc:985:30: error: use of deleted function ‘YYSTYPE::YYSTYPE()’
YYSTYPE yyvsa[YYINITDEPTH];
^
union {
std::shared_ptr<BlockNode> blockNode; //not allowed
std::shared_ptr<Node> *testNode; //allowed
}
union {
Node *testNode;
}