[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: C++11 move semantics

From: Frank Heckenbach
Subject: Re: C++11 move semantics
Date: Thu, 08 Mar 2018 00:33:46 +0100

Hans Åberg wrote:

> > Sure, it's not required (nothing about the C++ mode is), but it
> > might be convenient for the user as it avoids a trap. I have a
> > number of such rules in my grammars, and if you hadn't mentioned it,
> > I'd have been caught by this, not even at compile-time, but at
> > runtime. (Though such a bug would probably be rather obvious and
> > easy to fix in all places, not the end of the world.)
> It should complain if not having a not supported semicolon.

Not sure I follow you here. If I have a rule like "foo: bar;" where
foo and bar have the same (non-void) type, the C skeleton does
"$$ = $1"; the standard C++ skeleton just default-initializes $$
(so it will not be undefined, just empty). My patch does
"$$ = std::move ($1)" (effectively).

> It might be good to be able to change container, C++ perhaps sues
> a deque for stack as copying might be expensive.

Since std::stack moves instead of copying when possible, not quite
so expensive. Also bison by default reserve()s 200 entries, and I
think you rarely need a parser stack deeper than this, so this might
be a theoretical problem.

> >> Using inline functions for the actions might do it. The compiler
> >> can then remove the inlines, but the moves should be still applied
> >> correctly. Or maybe not, depending on how the C++ standard is
> >> written.
> > 
> > AFAIK, it allows for (and modern compilers do) automatic moving for
> > the return value only. So inline functions would help in cases such
> > as the default action ("$$ = $1", if "$$ =" was replaced by "return"
> > and "$1" was a function parameter), and similar cases such as
> > "$$ = $2" (which typically occurs in rules such as '(' expr ')')
> > where a default action doesn't help.
> Perhaps if it know that $1 expires, it can apply a move assignment.

It could do that if $1 is mentioned only once. In fact, I just
checked my grammars and in almost all cases that's so (not counting
a later "free ($1)" or "delete $1" which is part of the manual
pointer management which would disappear with unique_ptr); for me
that's because I prefer to keep my actions short and do all
non-trivial work in subfunctions.

It's still not a silver bullet: Others might prefer longer actions
that regularly mention $n more than once, and even I have at least
one such rule, basically:

  a: b c { $$ = $2.empty () ? $1 : combine ($1, $2); };

Here, moving from $1 would be safe in both places as only one is
executed; moving from $2 is safe in the combine() call, not in the
empty() call (but also not required, since empty() is a const member
function). That's not too difficult for a programmer to see, but
almost impossible for Bison to do automatically.

Of course, Bison could give up there (and possibly warn about it),
and still do automatic moving in other situations.

> > I think it's an interesting idea, also for syntactic reasons:
> > Writing "return" instead of "$$ =" seems more natural (though of
> > course, you have to watch out: "$$ =" can be followed by other
> > statements, "return" cannot, so Bison couldn't simply replace it,
> > but a user can deal with it). Also functions could have named
> > parameters (which you seem to prefer anyway) always instead of "$1"
> > etc. So if I'd design Bison now, that's probably what I'd do. But
> > given things as they are, this might be too big a change, both to
> > implement, and for many users to adopt.
> I though of it just as an implementation, but whatever.

I did so at first, but then I realized that Bison would have to
replace "$$ =" with "return" which is dangerous as I said. So it
would probably be easier in the long run to leave this to the
programmer. (But again, I doubt this will be implemented.)

> [GC]
> I use it for dynamic polymorphism like in Scheme/Guile, where you
> can't tell when the object expires.

shared_ptr also does it (and I used it where I need it), but ...

> Where automatic objects can be used, that is better.

... indeed, most of the time, automatic objects or unique_ptr
suffices for me and I prefer to use it.

> > 3. shared_ptr: Has the performance problems as I described.
> I don't recall this.

Lack of release method, so it would propagate throughout all my
code. See first mail in thread.

> > 4. A manually made shared pointer which a release method. That's
> >   possible to implement, and since I don't need all the advanced
> >   features of shared_ptr, it would be easier than a full
> >   reimplementation of shared_ptr, but still some work.
> > 
> > Now, I might do 4. if it was my only choice because 2. didn't work.
> > But so far it looks like 2. does work with relatively small changes
> > to the skeletons, and it's a more general approach, and hopefully
> > more useful to user users (if accepted upstream).
> I used that before switching to a GC, but in reality, I never used
> the detach function. It is very complicate to keep track of.

So we basically agree. I wouldn't like to do it easier, and proper
move semantics allow me to avoid it.

> >> Since C++17 now is available and supported by GCC7, std::variant would be 
> >> best to use.
> > 
> > Agreed. It will require some changes to the code using it, but it
> > will actually make it simpler.
> And more reliable, as the compiler developers pay attention to it.

And more type-safe. std::variant checks more at compile-time that
Bison's variant doesn't.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]