2

As I have a class like:

 class Test {
   void setVersion(Version *version);
   Version* version() const;
   private:
      Version *m_version;
 };

which I adapted using BOOST_FUSION_ADAPT_ADT I'd like to know how I could write grammar rules which return Version objects on heap without leaking on failing. One way I've discovered is to use

 [_val = phoenix::new_<Version>(Version(0))]

in semantic actions but this seems rather like a dirty workaround to me. Note that usually I wouldn't use heap allocated objects but in this case the API with pointers is already fixed that way.

Baradé
  • 1,290
  • 1
  • 15
  • 35

1 Answers1

1

So many knee-jerk reflexes coming up here:

  1. indeed, don't use pointers here
  2. Rule Of Zero

I mean, rethink your problem. Yes I can think of a few ways in which you can hack around the problem of leaking on backtracking, but they're all ugly, error-prone, and most importantly probably unneeded.

Let's think this over.

  1. Why would Version by referred to - by non-owning pointer?

    Well, the most reasonable explanation would be that version could have largish attached data and other things (serialization strategies, logging, validation struff etc. Version could add any runtime-polymorphic behaviour imaginable into the mix).

    This information would be "external" to any objects that "belong" to a version, so it makes sense that this version "meta information" would not be owned and referred to polymorphically.

  2. What does this mean?

    In my view this likely means that any Versions that could occur during parsing would have to be already known at the start of parsing. In that case, there would be no need to dynamically construct (many many, potentially duplicate) instances of Version at all, during parsing.

  3. Yeah, but what if it's not?

    Let's say you don't have this "table of versions" available at the start. In all likeli-hood, you don't want each node in the AST to end up with their own unique instance of Version even if it refers to the same version. Therefore, you should probably make a factory function that

    • maintains a "shared" table of (unique) versions
    • is able to look up version items during parsing (so you can set the Version* in your parsed nodes)
    • optionally instantiates a new Version object if - and only if - it's not yet present at the time of lookup

    Now this table can be the owner of all Version instances, and can simply free them all at once when you're done with them.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Now, if I would use shared pointers I probably would have the same problem except for the leaking point. My question is more about how I can return a heap allocated struct/shared pointer from a rule still using %= operator and the adapted struct of version with getters and setters. I do not want to use the phoenix semantic action if possible. – Baradé Apr 22 '14 at 13:24
  • How can you not? `rule myrule = qi::eps [ qi::val = phx::new_() ];` does exactly that. Also note, I did *not* suggest you use shared pointers (for the simple reason that you said you couldn't alter the classes). – sehe Apr 22 '14 at 13:25
  • @Baradé In case it interests you, I have just created an approach that uses heap-allocated values - safely - **[here](http://stackoverflow.com/questions/23299722/how-can-i-use-polymorphic-attributes-with-boostspiritqi-parsers/23301519#23301519)**. Perhaps you can use this, if only for ideas? – sehe Apr 26 '14 at 00:13
  • that's very interesting though it would be nicer to have standard solution/pattern like using boost::recursive_wrapper. Is there any way to do this without writing the custom type "CommandHolder" and using a standard type? only for simplyfing the code – Baradé May 03 '14 at 00:10
  • If you want to simplify the code, use value semantics. It's in the design of the library. If you don't want to, just roll your own parser. It's a trade-off. – sehe May 03 '14 at 00:42
  • Hello, it's me again. I put some effort into working on a solution with shared pointers or unique pointers. The problem is that with shared pointers I have to "release" operation and unique pointers are not supported by Boost Spirit: http://boost.2283326.n4.nabble.com/spirit-and-std-unique-ptr-td3738224.html – Baradé May 07 '14 at 13:19