[Top][All Lists]

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

Re: C++11 move semantics

From: Hans Åberg
Subject: Re: C++11 move semantics
Date: Thu, 8 Mar 2018 10:18:18 +0100

> On 8 Mar 2018, at 00:33, Frank Heckenbach <address@hidden> 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).

We are speaking about different things here: In Yacc grammar one drop the ";".

>> 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.

The type std::stack is older, but some benefits of std::deque are mentioned 

>>>> 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 would be complicated, so just std::move for now.

>>> 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.)

And maybe the C++ standard does not admit one relying on it.

>> [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 ...

The std::shared_ptr is simplistic, and the more advanced variation I used 
turned out to be too complicated.

>> 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.

A GC possibility is isolate object with known lifetime and register those with 
pointers into the GC heap.

>>> 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.

I am not sure why you need it in the parser. Just put the object on the heap 
and use shared_ptr in the semantic value, but nowhere else.

>>>> 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.

You may do your own M4 files, and as Bison isn't development, there is no risk 
for it to become outdated, and maybe get it integrated later.

reply via email to

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