【问题标题】:Bison value moving / efficiency野牛价值移动/效率
【发布时间】:2016-07-07 04:08:30
【问题描述】:

我正在从野牛的语义值构建我的解析数据结构。一种特殊的结构是std::vector<double> 类型。我很好奇野牛内部如何处理移动的语义值。我尝试分析c++.m4文件,发现:

template <typename Base>
  inline
  void
  ]b4_parser_class_name[::basic_symbol<Base>::move (basic_symbol& s)
  {
    super_type::move(s);
    ]b4_variant_if([b4_symbol_variant([this->type_get ()], [value], [move],
                                      [s.value])],
                   [value = s.value;])[]b4_locations_if([
    location = s.location;])[
  }

不幸的是,我无法理解这一点,无法确定移动 std::vector 等数据结构的效率,部分原因是我对 m4 语法一无所知。

在我的语法中考虑到这一点:

%define api.token.constructor
%define api.value.type variant
%type < std::vector<double> > numlist
...
numlist:
    num             { $$ = std::vector<double>(); $$.push_back($1); }
|   numlist "," num { $$ = $1; $$.push_back($3); }
;

我不确定性能影响。请注意,这将使用 C++98 编译器而不是 C++11 编译器进行编译;因此不会有移动语义。

我猜$$ = std::vector&lt;double&gt;() 语句可以被删除;我认为它已经是默认构造的,但我没有测试过,我不确定野牛的内部变体类型是如何工作的。我特别感兴趣的是$$ = $1; $$.push_back($3); 是否会为每个要添加的项目复制矢量?

我无法确定是否需要将类型切换为std::vector&lt;double&gt; *;诚然,使用 bison 的变体类型背后的大部分原因是使用纯 C++ 类型而不是指针联合。


我对实际上使用 C++11/14 尤其是 std::unique_ptr 的解析器也有类似的好奇心。如果分配了一行左递归规则,比如$$ = std::make_unique&lt;...&gt;(...),那么下面的代码是否能够执行$$ = $1; $$-&gt;...

【问题讨论】:

    标签: c++ vector c++14 bison move-semantics


    【解决方案1】:

    我不是 Bison / Yacc 专家,但您可以查看生成的代码:

          {
      case 2:
    #line 20 "test.yy" // lalr1.cc:846
        { yylhs.value.as<  std::vector<double>  > () = std::vector<double>();
          yylhs.value.as<  std::vector<double>  > ().push_back(yystack_[0].value.as< double > ()); }
    #line 1306 "test.tab.cc" // lalr1.cc:846
        break;
    
      case 3:
    #line 21 "test.yy" // lalr1.cc:846
        { yylhs.value.as<  std::vector<double>  > () = yystack_[2].value.as<  std::vector<double>  > (); 
          yylhs.value.as<  std::vector<double>  > ().push_back(yystack_[0].value.as< double > ()); }
    #line 1312 "test.tab.cc" // lalr1.cc:846
        break;
    

    位于parser::parse 方法中,其中yylhsstack_symbol_type 类型的局部变量,yystack_parser 类型stack_type 的属性(其中包含stack_symbol_type) .

    看起来答案是是的,当您执行$$ = $1 时,整个向量将被复制,我看不出编译器如何优化这一点。 as的声明如下:

    template <typename T>
    T& as();
    

    使用const 变体,因此对T 类型进行了处理,在您的情况下为std::vector&lt;double&gt;,因此制作了一个副本。即使您使用 移动语义,也会制作副本,因为 RHS 不是 xvalue

    【讨论】:

    • 谢谢!我真的很想避免创建指向向量的构造,但看起来这是最好的做法。
    • @Zac 你考虑过交换$1$$ 而不是分配吗?
    • @Michael 我没有。你指的是 std::swap() 吗?
    • @Zac 我打算引用 Holt 引用的成员函数 swap,但是标准库应该重载全局 swap 以调用向量的成员函数,因此任何一种方式都应该有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多