提升业障:这种对transform_attribute的隐式调用如何工作? (还是不?) [英] Boost karma: how does this implicit call to transform_attribute work? (or doesn't?)

查看:113
本文介绍了提升业障:这种对transform_attribute的隐式调用如何工作? (还是不?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下一段代码似乎运行良好(我基于将已解析的变量与提升因果报应一起使用)。

I have the following piece of code that seems to work fine (I based the semantic actions on reuse parsed variable with boost karma).

#include <iostream>
#include <iterator>
#include <memory>
#include <string>
#include <vector>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/sequence.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/support_attributes.hpp>
#include <boost/spirit/include/support_adapt_adt_attributes.hpp>

using namespace boost::spirit;

struct DataElement
{
  DataElement(const std::string& s) : str_(s) {}

  const std::string& str() const { return str_; }
  std::string& str() { return str_; }
  std::string str_;
};
using Data = std::vector<std::shared_ptr<const DataElement>>;

namespace boost {
  namespace spirit {
    namespace traits {

      template<>
      struct transform_attribute<std::shared_ptr<const DataElement> const, const DataElement&, karma::domain>
      {
        using type = const DataElement&;
        static type pre(const std::shared_ptr<const DataElement>& val) { return *val; }
      };

    }
  }
}

BOOST_FUSION_ADAPT_ADT(
  DataElement,
  (std::string&, const std::string&, obj.str(), obj.str())
  );

template<typename Iterator>
struct TheGrammar: public karma::grammar<Iterator, Data()>
{
  TheGrammar(): karma::grammar<Iterator, Data()>(start)
  {
    start %= -(elt % karma::eol);
    elt %=
      karma::lit("'some prefix'")
      << karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)]
      << karma::lit("'some infix 1'")
      << karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)]
      << karma::lit("'some infix 2'")
      << karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)]
      << karma::lit("'some suffix'")
      ;
  }

  karma::rule<Iterator, Data()> start;
  karma::rule<Iterator, const DataElement&()> elt;
};

int main(void)
{
  Data vec = {
    std::make_shared<DataElement>("one"),
    std::make_shared<DataElement>("two"),
    std::make_shared<DataElement>("three"),
    std::make_shared<DataElement>("four"),
    std::make_shared<DataElement>("five"),
    std::make_shared<DataElement>("six"),
    std::make_shared<DataElement>("seven"),
    std::make_shared<DataElement>("eight"),
  };
  using iterator_type = std::ostream_iterator<char>;
  iterator_type out(std::cout);

  TheGrammar<iterator_type> grammar;
  return karma::generate(out, grammar, vec);
}

我想了解几件事:


  1. 为什么我不需要在任何地方使用 karma :: attr_cast ?我的 start 规则是 std :: shared_ptr 的向量,而 elt 规则适用于实际对象const引用。我最初尝试使用 attr_cast ,但是却无济于事,只是为了以防万一,它只是半心半意地尝试了这个版本,并且它起作用了...

  2. 如果我将我的自定义 transform_attribute 全部注释掉,为什么它仍然可以编译?是否提供了一些默认的 std :: shared_ptr< T> -> T& transform_attribute?我找不到很多东西,但是也许我找不到合适的地方?

  3. 如果我注释掉自定义的 transform_attribute ,如上所述,该代码仍在编译,但是在运行时显然存在一些内存损坏。 karma :: string 会生成垃圾。从某种意义上讲,我可以理解一定会发生一些有趣的事情,因为我什至没有告诉业力如何从我的 shared_ptr 到达对象。它会编译实际的错误/错误吗?

  1. Why don't I need to use karma::attr_cast anywhere? My start rule is a vector of std::shared_ptr whereas the elt rule works on the actual object const reference. I originally tried attr_cast but got nowhere, and sort of tried this version only halfheartedly just in case it worked, and it worked...
  2. Why does it still compile if I comment out my custom transform_attribute altogether? Is there some default std::shared_ptr<T> -> T& transform_attribute provided? I couldn't find much, but maybe I'm not looking int the right place?
  3. If I comment out my custom transform_attribute, as mentioned above, the code still compiled, but there's clearly some memory corruption at runtime. The karma::string generate garbage. In a way, I can understand that something funny must be happening since I don't even tell karma how to get from my shared_ptr to the objects. Is the fact that it compiles the actual error/bug?

非常感谢您的时间和帮助!

Thanks a lot for your time and help!

推荐答案


  1. 每个规则对声明的属性类型都有隐式的attr_cast

  2. Spirit的类型兼容性规则一直处于混乱状态。我所看到的只是字符串类型是一个容器。它会复制-构造似乎长度为97332352的std :: string。这并不奇怪,它本身是错误的,并且会触发UB,因为最终将范围传递给 memset 重叠:


Source and destination overlap in memcpy(0x60c1040, 0x5cd2c90, 97332352)
   at 0x4C30573: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x401B26: copy (char_traits.h:290)
   by 0x401B26: _S_copy (basic_string.h:299)
   by 0x401B26: _S_copy_chars (basic_string.h:342)
   by 0x401B26: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) [clone .isra.53] (basic_string.tcc:229)
   by 0x402442: _M_construct_aux<char*> (basic_string.h:195)
   by 0x402442: _M_construct<char*> (basic_string.h:214)
   by 0x402442: basic_string (basic_string.h:401)
   by 0x402442: call<const boost::spirit::unused_type> (extract_from.hpp:172)
   by 0x402442: call<const boost::spirit::unused_type> (extract_from.hpp:184)
   by 0x402442: extract_from<std::__cxx11::basic_string<char>, boost::fusion::extension::adt_attribute_proxy<DataElement, 0, true>, const boost::spirit::unused_type> (extract_from.hpp:217)
   by 0x402442: extract_from<std::__cxx11::basic_string<char>, boost::fusion::extension::adt_attribute_proxy<DataElement, 0, true>, const boost::spirit::unused_type> (extract_from.hpp:237)
   by 0x402442: pre (attributes.hpp:23)



  • 是的,这是一个QoI问题。

  • Yes, that's a QoI issue.

    问题经常出在c ++的隐式转换上。指针类型有许多意外的转换。共享指针的上下文确实转换为bool。

    The problem often is with c++'s implicit conversions. Pointer types have many unexpected conversions. Shared pointers do have their contextual conversion to bool.

    更多说明:


    1. 您的融合适应似乎有缺陷: val 在二传手中没有使用

    BOOST_FUSION_ADAPT_ADT(DataElement, (std::string &, const std::string &, obj.str(), obj.str() = val))
    


  • 您正在做很多我已经学会避免的事情。

  • You're doing many things I've learned to avoid.

    • I prefer to have semantic-action-less rules: Boost Spirit: "Semantic actions are evil"?
    • I don't do shared-pointers in Spirit grammars/generators How can I use polymorphic attributes with boost::spirit::qi parsers? (arguably, in a generator setting it's less of a problem!)
    • I don't do ADT adaptation (it's too easy to get bitten with UB) Error when adapting a class with BOOST_FUSION_ADAPT_ADT

    这篇关于提升业障:这种对transform_attribute的隐式调用如何工作? (还是不?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆