[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: Tue, 6 Mar 2018 10:05:26 +0100

> On 6 Mar 2018, at 00:24, Frank Heckenbach <address@hidden> wrote:
> Hans Åberg wrote:
>>> On 5 Mar 2018, at 18:15, Frank Heckenbach <address@hidden> wrote:
>>> Let's see if I can add "$$ = std::move ($1)" as a default action in
>>> my patches. (Not as a pre-action as in C, that would be wrong with
>>> move, only as a default action when no user action is supplied.)
>> That might be OK in this special case.
> No special case, I implemented it fully generally in the C++11
> template (my previous patch).

I meant the special case of a default action, as it is harder to deduce when 
std::move should be applied.

Perhaps wrapping the actions in inline functions might get C++ to apply moves 
correctly (see below).

>>> So I see no reason why it shouldn't be done by default, especially
>>> since in C that's not a Bison quirk, but actually a Yacc feature.
>> I got the impression it might be complicated to implement.
> I had feared so, but as you can see, it wasn't. (And it would get
> even easier with std::variant.)

Otherwise, there is no reason for Bison to be Yacc compatible, except for the 
special Yacc mode, which Paul Eggert worked on becoming POSIX compliant. For 
example, Yacc has optional rule colons, but that might have been removed in 
Bison in some modes at least. And Bison now has grammar variable naming, as I 
indicated, which in fact is very convenient.

>>> That's unrelated. std::vector does all the std::move's it needs
>>> internally.
>> This f you might want to avoid tweaking the M4 file and just change the 
>> container.
> Again, changing the container does not help. The parser needs move
> semantics in other places, and once they're implemented (which I
> did), vector just works!

C++ std::stack though has std::deque as default. If one wants to access 
elements not on top, std::stack does not work, though. 

>>> In user actions, one needs std::move regardless, e.g.
>>> "$$ = std::move ($1)" (like the default action) or something like
>>> "$$ = build_something (std::move ($1), std::move ($2))" with some
>>> user-defined build_something function. That's not poor design; such
>>> code is expected when using move-only types. But again, the user
>>> actions are not the issue, bison can't do anything there anyway
>>> (except for the default action, see above). The required moves
>>> within the parser are the problem.
>> It seems to be forced that way, but ideally, the moves should be hidden away 
>> in containers.
> We're talking about user-actions here. To them, $$, $1, etc. do and
> should behave just like varibles. (That $1 is an element of a
> container is irrelevant, and again, there's no difference between
> vector and deque in this regard.) The user action might use them
> twice ("foo ($1); bar ($1);"), so always moving would be wrong. It's
> up to the user to move when wanted. And it's not really a problem --
> with a move-only type, the compiler will complain when you forget
> it.

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.

>>> GC doesn't call destructors, does it?
>> One can a could of different things with the Boehm GC, register
>> finalizers, and it also a deallocation function.
> If you have to register them explictly, all the beauty of RAII is
> lost.

One can mix both GC and standard stack allocations. Guile uses now the Boehm 
GC, and I have a similar dynamic polymorphy. For that I wrote a template 
reference class. The use of finalizers did not seem to impose a significant 
overhead. They are otherwise only needed so collect non-memory resources, such 
as open streams.

Then the problem is if that a standard container has such a GC collected 
reference, then the GC cannot trace the pointer and keep it alive if not using 
its allocator and deallocator, so that pointers that should be alive might be 
collected. This does indeed happen, resulting in mysterious memory errors.

>>>> and shared_ptr might be an alternative.
>>> Not for me (in many cases), as I explained.
>> You will have to explain it again.
> http://lists.gnu.org/archive/html/bug-bison/2018-03/msg00002.html
> Though I don't understand why we need to argue this.

Just to let me follow. You did not explain why you can't allocate the move-only 
type on the heap, and keep a pointer.

I used a reference count for two functions: polymorphy, and optimizing by 
avoiding copying. For the polymorphy, I switched to the GC, and for simple 
types, standard automatic objects relying on C++11 move constructors. These 
changes were made to be able to keep the program together semantically, thus 
accepting some overhead. For the switch to automatic objects, that was not so 

> Others on the
> list have requested move semantics, and you put some work into it
> yourself, so it seems obvious they're useful (just like most modern
> C++ is based on them).

I just moved along and give advice given the current state of lack active Bison 
development. If you want to fix this, that would be best, but I do not know how 
to get it into the Bison releases - perhaps Paul Eggert can help out.

>>>> It is not difficult to hack the M4 file, but if one writes the
>>>> parser, not actively develops for awhile, and Bison changes it,
>>>> then that may turn out be a hurdle say in a few years time.
>>> Exactly. That's why I hoped to see a maintainer here.
>> I can't help you. The CC you removed was to one of them.
> I didn't remove any CC. You CC'ed one (short) mail to Paul Eggert
> which just said that Akim Demaille has not been active for some time
> now. I hadn't replied to that mail, but to the main thread which was
> not CC'ed.

I did not see his reply. Paul Eggert only programs C, but he might help you to 
get changes into the Bison distribution.

>>>> I do not remember, so you would have to search the list archives. I am 
>>>> just saying there might a risk there.
>> Maybe "C++17" then.
> Found it, I suppose that's what you mean:
> http://lists.gnu.org/archive/html/bug-bison/2017-06/msg00000.html

Yes, that seems so.

> Indeed, it seems it doesn't work with $<...>. I didn't notice
> because I never use this feature. (When I need a temporary value
> from a mid-rule action, I turn it into a nonterminal instead; seems
> more type-safe to me, no need to manually match the type on
> assignment and usage.)
> Bison's variant implementation really breaks down here. One could
> work around it with some extra code to keep track of the dynamic
> type of $<...>, but that gets really close to reimplementing
> std::variant, so it seems rather pointless. So std::variant is the
> way to go, at least in the long run. (As I said, I don't use gcc7
> set, but I don't require $<...>, so for now I'll be fine with
> Bison's variant.)

Since C++17 now is available and supported by GCC7, std::variant would be best 
to use.

reply via email to

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