A bit of background for the default comparison proposal -- Bjarne Stroustrup

In 2014, Oleg Smolsky proposed to add default member functions defining comparisons. That re-ignited a decades-old debate. I once asked Dennis Richie why C didn’t provide a built-in == (equality) the way it provides a built-in = (copy). The answer was that until 1978 C didn’t have = for structs either, and copying could be efficiently implemented by something like memcpy(), but comparison couldn’t because the layout of structs included “holes” caused by alignment that had to be ignored. The days where compilers could handle individual members one by one and still generate optimal code for them were still far in the future, so I postponed dealing with comparisons. If you wanted one, you could write it yourself. That’s true, but many people, including Alex Stepanov, have objected to the inconvenience.

The killer argument for default comparisons is not actually convenience, but the fact that people get their equality operators wrong. They forget to compare all elements (especially when updating a struct with a new member). Also, given inheritance, a X::operator==(const X&) is easy to misuse (whether virtual or not). We get slicing (b==d will work even if b and d are of different classes in a hierarchy, and usually give a wrong answer). If people define operator==() as a member; then the left- and right-hand operand obey different conversion rules. Also, defining the semantics for == and != is relatively simple, but there are subtleties about other operators, such as <=; does its meaning involve < and == or < and !? Contrary to “common knowledge” there seems to be little difference in performance.

Lots of people joined the discussions and the discussions went all over the place. How do we handle pointers? (we don’t), how do we handle mutable members?, should we use static reflection?, etc., etc., At times, I thought that we would get nothing. That wouldn’t be a tragedy because default comparisons are not on my (mostly mythical) top-20 list of desirable improvements to C++. However:

  • I started trying to design == in analogy to = as if Dennis and I had been doing it in 1980 or so.
  • Jens Maurer helped us with wording, making sure the rules were consistent.
  • Herb Sutter helped ensure that lookup rules were sane from a programmer’s point of view.

Using namespaces and operator==(), you can (today) construct programs for which a==b is true in one place and false in another. That’s unavoidable if you treat == as an ordinary function. But == is not ordinary! Its semantics is fixed by the rules of logic (we cannot have both a==b and a!=b), and its meaning must match that of copying (e.g., after a=b we must have a==b). Secondly, slicing is evil. Defining = in terms of references was a mistake. As far as I can remember, this is the only place in C++ where I made a change based solely on the advice of a theoretician: “OO is based on references, so for uniformity == should be based on references.” But there is nothing OO about ==! Each class (in a hierarchy or not) has its own ==, just like it has its own =. You can define “odd” assignments and comparisons yourself. That’s your problem, but the default must be sane and safe.

Jens suggested the obvious solution: just ban slicing for both == and =. I had shied away from this incompatible change, but the result is beautiful. If the committee approves, we have a coherent set of rules and we eliminate some subtle nasty bugs! To preserve the techniques of tag dispatching, the rule is that you cannot slice if the derived class has added a non-static data member. That is, the derived to base conversion works unless it produces a sliced object.

CppCon 2016 registration is open

The early bird registration for the upcoming CppCon 2016 in September is open.

 
 

Early Bird registration

The big new is that there are six classes that will be held on the Saturday and Sunday before the conference. Attendees can choose between classes on the Core Guidelines, concurrency, embedded developement, C++11/14, Qt/Widgets, and low-latency programming taught by some of the best instructors in the industry.

Registration opportunties also include a field trip to Seattle's Living Computer Museum, attending the Standards Committee's Study Group on game development and low-latency, and getting logo'ed shirts.

Cheerp PreExecuter: compile-time evaluation of constructors--Sander Mathijs van Veen

An advancement in the world of C++ to javascript:

Cheerp PreExecuter: compile-time evaluation of constructors

by Sander Mathijs van Veen

From the article:

The size of a JavaScript web application, especially when compiled from a complex C++ source, has a key role on the quality of the user experience, being directly connected to the download and startup time. Size also has a big impact on the traffic and bandwidth needs of the hosting server, which translates one to one into costs. Therefore, minimizing the size of JavaScript applications compiled from C++ with Cheerp has always been one of our priorities...

Automatic event cleanup in C++--Nercury

How to handle events?

Automatic event cleanup in C++

by Nercury

From the article:

Event subscriptions have a downside: someone has to unsubscribe. Usual approach is to make sure it happens when the subscibtion is no longer needed.

But, can we do it automatically, in a way that is easy to use and extend?

Let's see how it can be done in C++...

New Options for Managing Character Sets in the Microsoft C/C++ Compiler--Jim Springfield

A new post from the Visual C++ team about how VC++ has evolved in the past for supporting different characters sets, and what's new:

New Options for Managing Character Sets in the Microsoft C/C++ Compiler

by Jim Springfield

From the article:

The Microsoft C/C++ compiler has evolved along with DOS, 16-bit Windows, and 32/64-bit Windows.  Its support for different characters sets, code pages, and Unicode has also changed during this time...

N4578-79: Parallelism TS2 proposed working draft

New WG21 papers are available. If you are not a committee member, please use the comments section below or the std-proposals forum for public discussion.

N4578: Working Draft, Technical Specification for C++ Extensions for Parallelism Version 2 (Jared Hoberock)

N4579: Parallelism TS Editor’s Report (Jared Hoberock)

N4578 is the proposed working draft of Parallelism TS Version 2. It contains technical changes to the Parallelism TS to apply the following revision:

  • P0155R0 - Task Block R5

N4578 updates the previous draft, N4505, published in the post-Lenexa mailing.

Technical Changes

  • Applied P0155R0, which introduces support for fork-join task parallelism

via task blocks.

 

A bit of background for the operator dot proposal -- Bjarne Stroustrup

Over the years, there have been several suggestions and proposals for allowing programmers to define operator.() so as  to be able to provide “smart references” similar to the way we provide “smart pointers.” I first considered that in 1983, but couldn’t solve the problem. In early 2014, Gabriel Dos Reis and I decided that now we really had to solve it: Too much code was getting too complicated and too ugly because of the lack of smart references. Operator -> is good for objects with pointer semantics, but we needed a general way of providing value semantics for a handle.

Operator dot differs from other operators by having its right-hand operand be a name rather than a value: for x.m, m is not the value of some variable it is the name of a member of some class. Ideally, dot would be a binary operator taking into account both x and m for x.m. Many have tried, including Gaby and I, but that quickly gets complicated. The current rules for operator->() and the proposed design for operator.() “solves” those problems by considering the right-hand operand only when looking for possible candidates. This allows composition of interfaces without requiring inheritance. If someone figures out a good and simple way of taking the member name into account in a more general form, we are reasonably sure that we have not proposed anything that prevents that. When designing, you must always try to avoid painting yourself into a corner by closing off possible evolution paths.

Historically, the key sticking point with the operator.() proposals has been how to distinguish operations on the reference object (the handle) from operations on the referred-to object (the value). The current proposal “forwards” every operation to the referred-to object unless that operation has been explicitly declared in the handle. This is simple and quite general. In particular, we can apply operators on a smart reference (e.g., ++r) and have ++ apply to reference is we so desire, but by default it is applied to the referred-to object (as it would for a built-in reference). The papers outline why we think that this is – by far – the design that best balances the needs of the various use cases. The focus is on allowing the user to define a class that is a reference, just like the built-in reference, except that it is “smart” in some way (e.g., it can have a rebind() member) analogously to the way a “smart pointer”  is just like a pointer except that it is “smart” in some way (e.g., takes care of ownership). If you can define or use a smart pointer, you can define or use a smart reference.

The proposal has been quite stable. There have been proposals for alternatives and major extensions, but few suggested modifications. We tried to find a way to prevent a pointer (or reference) to the referred-to object to escape from the smart reference, but couldn’t find a simple way of guaranteeing that so we gave up, quoting “C++ protects against Murphy, not Machiavelli.” We ensured that you can define a matching set of smart . (dot), -> (arrow), * (dereference), and [] (subscript) operators with the relations they have for built-in types.

RAII without exceptions--Eli Bendersky

Is RAII in C++ only possible with exceptions? Eli Bendersky clarifies the matter:

C++: RAII without exceptions

by Eli Bendersky

From the article:

this post is not about whether exceptions are good or bad. What it is about is RAII as a C++ dynamic resource management technique that stands on its own and is useful with or without exceptions. In particular, I want to explain why RAII is indeed useful even if you have exceptions disabled in your C++ code...