[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: Wed, 7 Mar 2018 14:45:59 +0100

> On 6 Mar 2018, at 23:48, Frank Heckenbach <address@hidden> wrote:
> Hans Åberg wrote:
>> 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.
> 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.

> But if fixing
> the behaviour (especially with std::variant) is not more effort than
> fixing the documentation (which should be done otherwise), why not
> fix the behaviour?

The variants should be fixed, but there seems to be no developers right now. 
Default actions are good if not difficult to implement, but personally I don't 
rely on them.

>> C++ std::stack though has std::deque as default. If one wants to
>> access elements not on top, std::stack does not work, though.
> Which Bison needs to do, so std::stack is out.


> But Bison's stack
> implementation is rather short and unproblematic (and it can also
> work with std::deque -- I still don't see an advantage of doing so,
> but if you insist, you could probably add a %define or #define to
> use it).

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

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

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

> So I'm not sure it's worth the effort. But if, say, a lot of users
> now scream they want this feature, I might actually take a stab
> trying to implementing it ... :)
> I wouldn't mind my grammars to look this way. But just to be sure,
> this still doesn't eliminate the need for manual moves in many cases
> such as "$$ = myfunc (std::move ($1), std::move ($2))", where myfunc
> might be a typical builder function that wants to take ownership of
> its arguments.

It is an interesting idea, though.

>>>>> 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.
> Stack allocations are no problem. It's about heap allocations. My
> programs have very many of them, and most of them outside of the
> parser. Even if GC can deal with them, it will slow it down, since
> it has to track all of them for liveness analysis, just to find the
> few dead ones. Also some of my programs have soft realtime
> requirements, so I prefer more deterministic behaviour.

All objects that have pointers into the GC heap must be tracked, and that 
includes container on the heap if they contain pointers to GC allocate objects.

>> 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.
> I destructors for various things, e.g. unregistering objects. I
> think RAII is a general way for any kind of cleanup; freeing
> resources is just a special case of it; freeing memory is a special
> case of the special case (though the most common one). GC set out to
> solve the special case. Unfortunately, RAII wasn't invented and
> fully understood until later; otherwise GC might never have seen
> widespead usage. I agree with most of what's written here:
> https://minorfs.wordpress.com/2011/04/29/why-garbage-collection-is-anti-productive/
> Or as http://viming.de/gc_vs_raii.html put it in the conclusion:
> RAII has many advantages over GC, while it solves problems that GC
> is supposed to solve as a "side-effect".

I use it for dynamic polymorphism like in Scheme/Guile, where you can't tell 
when the object expires. Where automatic objects can be used, that is better.

>> 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.
> What kind of pointer:
> 1. Raw pointer (manually managed): That's what I've been doing so
>   far. I don't need the C++ skeleton for this, the C one suffices.
> 2. unique_ptr: I'd like to, but it's move-only.
> 3. shared_ptr: Has the performance problems as I described.

I don't recall this.

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

>>> 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 did not see his reply.
> Sorry, my "which" (not "who") was referring to your mail, not to
> Paul Eggert (who hasn't replied so far). I will try to contact him
> again soon.

A problem seems to be that there is no developer at all right now.

>>> 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.
> 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. C++17 is a 
rather small addition, so perhaps it will be common before you finish.

reply via email to

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