C++ "allowed features" changes from the past 10 months

200 views
Skip to first unread message

Peter Kasting

unread,
Jan 18, 2018, 10:54:24 PM1/18/18
to Chromium-dev
As many of you are aware, Chromium lists the allowed subsets of C++11/14.  Since not everyone keeps constant track, here are the features that have been allowed since the last email I sent ~10 months ago.  There are a lot!
  • std::make_unique<>(), which should replace all existing usage of base::MakeUnique<>() and WTF::MakeUnique<>().  (And, in general, should be used in preference to bare new.)
  • Binary literals, so masks and bit-based constants can be written as 0b11010001 instead of 0xD1, where doing so would be more readable.
  • Literal separators in numeric constants, so that long constants like 0b10000000100000001000000010000000 can be broken into pieces like 0b10000000'10000000'10000000'10000000.
  • constexpr on more complex code, including code with conditionals and loops.  This allows marking more simple functions as constexpr.
  • Aggregate initialization of structs with default members, which allows structs with default values specified for some/all members to still be initialized with an aggregate of values.  This may be useful for unit tests which define structs to hold test case data, then initialize arrays of such structs, where many cases in the array have some identical fields.
  • std::next() and std::prev(), to increment and decrement copies of iterators by some value; these can be useful with non-random access types such as std::list, or when writing templated code that deals with different kinds of containers.
  • The no-parameter form of std::less<>, a function object for doing comparisons which can avoid some unnecessary temporaries in e.g. heterogeneous lookup.
  • std::shrink_to_fit(), which makes a non-binding request that a container reduce its capacity to match its size.
  • Tuple addressing by type, which allows calling std::get<> with a type parameter instead of a numeric one when doing so is unambiguous.  This can be useful for improving the readability of code which conceptually wants to say "get the string from this tuple" instead of "get the third element".
  • std::cbegin()std::cend()std::crbegin(), and std::crend(), which are constant counterparts to std::begin() and friends (which work like begin() member functions but can operate on e.g. array types as well).
  • The alignas() specifier and alignof() operator, which allow setting and querying the alignment for types.  Note that there are some usage caveats around alignas(); see the doc.
  • Functionality in <atomic>, which provides low-level atomic transaction functionality.  Very few people should need to use this directly; prefer higher-level synchronization primitives.
  • std::integer_sequence<>, which represents a sequence of integers as a type.  This is useful for certain kinds of template programming that I think relate to variable numbers of arguments?  (I dunno, I've never used this.)
Additionally, there are some changes to recommended best practices:
  • Move constructors should be declared noexcept where possible, since despite Chromium compiling with exceptions disabled, this affects things like whether std::vector can move instead of copy these objects.
  • With the removal of libstdc++, various features (e.g. std::get, std::map::emplace, <type_traits>, etc.) no longer have usage caveats around library bugs.
Finally, some features have been banned:
  • std::chrono literals, which are banned since <chrono> is banned.
  • thread_local, to mark a variable as thread-local, due to some surprising effects.  This may be allowed again in the near future, however.
  • Function return type deduction, which allows a function to be declared as returning auto (without a trailing return type).  This can currently cause infinite loops in clang; once that bug is fixed, it will likely be allowed.
  • Generic (or "polymorphic") lambdas, which allow the use of auto in declaring lambda parameter types.  As with function return type deduction, this can cause clang bugs and may be allowed when those are fixed.
As always, to propose allowing/banning your favorite feature, send mail to c...@chromium.org.

PK

Peter Kasting

unread,
Jan 19, 2018, 2:07:32 AM1/19/18
to Chromium-dev
On Thu, Jan 18, 2018 at 7:53 PM, Peter Kasting <pkas...@google.com> wrote:
  • std::shrink_to_fit(), which makes a non-binding request that a container reduce its capacity to match its size.
Pedantry: This should have omitted "std::", since it is a member function on the relevant containers/types and not a standalone function in the std namespace.

PK

Nico Weber

unread,
Sep 5, 2019, 1:45:39 PM9/5/19
to Peter Kasting, cxx
(chromium-dev to bcc, moving to cxx@)

This is a reply to an 1.5 year old email, but there's currently a mass-clang-tidy rewrite to add "noexcept" to all move ctors. I pushed back on this and several people sent me a link to the email this is replying to, so I wanted to open this up for discussion.

This mail says "move ctors should be declared noexcept", but https://google.github.io/styleguide/cppguide.html#noexcept actually says "Specify noexcept when it is useful and correct." -- that sounds more like "it's ok to use this when it makes sense", not "you should use this".

I think doing a mass rewrite isn't a great idea, because:

- There's hope to one day have the same semantic effect automatically when building with -fno-exceptions (e.g. https://reviews.llvm.org/D62228), and at that point this is just busy work

- gcc and clang have different requirements for noexcept, and auto-adding this everywhere increases the cost of keeping the gcc build going

- it adds visual noise

- most of the time it has no benefit


It's fine to add noexcept in cases where it provides measurable perf benefits, but I don't think we should do a mass codebase rewrite. We also should follow the google style guide that says "use when useful and correct", not "should".

Nico
--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CAAHOzFBPmS6Drun0dg5sy1Vw7W35rLc%2BF-oO32FZsPO0rGh7_Q%40mail.gmail.com.

Greg Thompson

unread,
Mar 8, 2020, 5:11:48 PM3/8/20
to Chromium-dev, pkas...@google.com, c...@chromium.org
Hi Nico. My understanding was that a move-only type required noexcept for it to be used in a vector (whereas an optional optimization path could be taken if the contained type was both copyable and movable w/noexcept). Is this correct? If so, it seems simpler to put noexcept on move-only types so that other folks don't have to come along later and add it when they want to use them in a std container. Wdyt?

Jan Wilken Dörrie

unread,
Mar 9, 2020, 3:59:56 AM3/9/20
to Greg Thompson, Chromium-dev, Peter Kasting, cxx
This understanding is not quite correct. std::vector commonly uses std::move_if_noexcept during its resize operation, which is a copy if the value (!is_nothrow_move_constructible && is_copy_constructible), and a move otherwise.

In particular this means the move constructor of both copyable and moveable should be marked noexcept, as otherwise vector will copy. If the type is move-only to begin with, std::vector will always move, as it can't copy anyway. noexcept doesn't hurt of course, which is why it usually is recommended on move-constructors. The style guide mentions this as well.

Best,
Jan

You received this message because you are subscribed to the Google Groups "cxx" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx+uns...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/cxx/710aeb1c-90ad-466c-9d9f-2cbb29966a7a%40chromium.org.

Greg Thompson

unread,
Mar 9, 2020, 5:26:37 AM3/9/20
to Jan Wilken Dörrie, Chromium-dev, Peter Kasting, cxx
On Mon, Mar 9, 2020 at 8:58 AM Jan Wilken Dörrie <jdoe...@chromium.org> wrote:
This understanding is not quite correct. std::vector commonly uses std::move_if_noexcept during its resize operation, which is a copy if the value (!is_nothrow_move_constructible && is_copy_constructible), and a move otherwise.

I was asking about move-only types, where falling back to a copy isn't an option. Does this not mean that a move-only type can only be stuffed into a vector if it can be moved (via move assign or move construct) without an exception being thrown? Or does vector have some other path where it'll do the move and let exceptions fly?

In particular this means the move constructor of both copyable and moveable should be marked noexcept, as otherwise vector will copy.

This is where the style guide makes things muddy: "You may use noexcept when it is useful for performance if it accurately reflects the intended semantics of your function". Where do we draw the line? Some (not me) might say "don't use noexcept unless you can demonstrate a performance hit by not using it."

But wait! I just noticed that the style guide follows that with "You can assume that noexcept on move constructors has a meaningful performance benefit." I read that as "always put noexcept on move ctors as long as it's actually correct." Should we not be doing this? If no, why not?

Jan Wilken Dörrie

unread,
Mar 9, 2020, 5:58:58 AM3/9/20
to Greg Thompson, Chromium-dev, Peter Kasting, cxx
On Mon, Mar 9, 2020 at 10:24 AM Greg Thompson <g...@chromium.org> wrote:
On Mon, Mar 9, 2020 at 8:58 AM Jan Wilken Dörrie <jdoe...@chromium.org> wrote:
This understanding is not quite correct. std::vector commonly uses std::move_if_noexcept during its resize operation, which is a copy if the value (!is_nothrow_move_constructible && is_copy_constructible), and a move otherwise.

I was asking about move-only types, where falling back to a copy isn't an option. Does this not mean that a move-only type can only be stuffed into a vector if it can be moved (via move assign or move construct) without an exception being thrown? Or does vector have some other path where it'll do the move and let exceptions fly?

If you put a move-only type in a vector and the move constructor is not marked noexcept std::vector::resize() will move, but waive its strong exception guarantee (this is mentioned in the notes of the linked article).  

In particular this means the move constructor of both copyable and moveable should be marked noexcept, as otherwise vector will copy.

This is where the style guide makes things muddy: "You may use noexcept when it is useful for performance if it accurately reflects the intended semantics of your function". Where do we draw the line? Some (not me) might say "don't use noexcept unless you can demonstrate a performance hit by not using it."

But wait! I just noticed that the style guide follows that with "You can assume that noexcept on move constructors has a meaningful performance benefit." I read that as "always put noexcept on move ctors as long as it's actually correct." Should we not be doing this? If no, why not?

Given that Chrome does not throw exceptions noexcept technically is always correct. I suppose so far we have refrained from a blanket "put noexcept on every move c-tor" because in most cases it is visual noise without much benefit. IIUC it only makes a difference when std::move_is_noexcept is used, and the type is also copyable. So far I only know of std::vector::resize making use of std::move_is_noexcept, so if you don't put your type in a vector you don't gain much.

However, back in the day the style guide wasn't as explicit in recommending noexcept move ctors, so maybe we should change our stance here.

Best,
Jan

Greg Thompson

unread,
Mar 9, 2020, 11:51:10 AM3/9/20
to Peter Kasting, Jan Wilken Dörrie, Chromium-dev, cxx
Now that the style guide is explicitly saying to do it, I think we should unconditionally add them to move ctors for new code where it's correct. This seems in keeping with our general "try not to deviate from Google style" guidance. I don't think this alone requires a mass refactor of existing code, though that would be nice to have.

On Mon, Mar 9, 2020 at 4:21 PM Peter Kasting <pkas...@google.com> wrote:
Note that your final paragraph has circled around to the original cause of this thread: a mass rewrite to do this everywhere and a debate over wherever we should be doing it. Nico makes the case for "why not". My position is still that we should do this everywhere.

PK

K. Moon

unread,
Mar 9, 2020, 12:02:24 PM3/9/20
to Greg Thompson, Peter Kasting, Jan Wilken Dörrie, Chromium-dev, cxx
Due to the lack of exceptions in Chromium, I agree that there's no practical effect (I believe the compiler will do the right thing when exceptions are turned off), so this seems purely a matter of consistency. On that basis, it seems like a good practice to adopt, but it's not urgent or anything.

Greg Thompson

unread,
Mar 9, 2020, 12:24:36 PM3/9/20
to K. Moon, Peter Kasting, Jan Wilken Dörrie, Chromium-dev, cxx
I seem to recall getting a compile error when trying to make a vector of a move-only type that was missing noexcept. Is my memory faulty?

Peter Kasting

unread,
Mar 9, 2020, 12:40:57 PM3/9/20
to K. Moon, Greg Thompson, Jan Wilken Dörrie, Chromium-dev, cxx
On Mon, Mar 9, 2020 at 9:00 AM K. Moon <km...@chromium.org> wrote:
Due to the lack of exceptions in Chromium, I agree that there's no practical effect (I believe the compiler will do the right thing when exceptions are turned off), so this seems purely a matter of consistency. On that basis, it seems like a good practice to adopt, but it's not urgent or anything.

Note that gcc (unlike clang) will fail to compile if you mark a move constructor noexcept when its implementation requires moving members whose move constructors are not themselves (recursively) noexcept.  So to the degree that there is still a community-supported gcc build, we need to be somewhat intentional when adding these (to either add them to whole hierarchies at once, or nowhere).

I think gcc's behavior is better than clang's here, honestly.

PK 

Peter Kasting

unread,
Mar 9, 2020, 2:17:04 PM3/9/20
to Greg Thompson, Jan Wilken Dörrie, Chromium-dev, cxx
Note that your final paragraph has circled around to the original cause of this thread: a mass rewrite to do this everywhere and a debate over wherever we should be doing it. Nico makes the case for "why not". My position is still that we should do this everywhere.

PK

On Mon, Mar 9, 2020, 2:24 AM Greg Thompson <g...@chromium.org> wrote:

K. Moon

unread,
Mar 9, 2020, 3:46:59 PM3/9/20
to Peter Kasting, Greg Thompson, Jan Wilken Dörrie, Chromium-dev, cxx
I threw together a Compiler Explorer link if anyone wants to play around with this: https://godbolt.org/z/IBvZTn

At least for my example, and with x86-64 clang-trunk, noexcept makes a difference with exceptions (as you'd expect), and makes no difference with -fno-exceptions (also as you'd expect, hopefully).

I poked around a bit with the gcc vs. clang behavior, but wasn't able to trigger the compilation error; I'm assuming I didn't hit the right set of conditions to trigger it.


José Dapena Paz

unread,
Mar 10, 2020, 6:24:36 PM3/10/20
to km...@chromium.org, Peter Kasting, Greg Thompson, Jan Wilken Dörrie, Chromium-dev, cxx
El lun, 09-03-2020 a las 12:45 -0700, K. Moon escribió:
I threw together a Compiler Explorer link if anyone wants to play around with this: https://godbolt.org/z/IBvZTn

At least for my example, and with x86-64 clang-trunk, noexcept makes a difference with exceptions (as you'd expect), and makes no difference with -fno-exceptions (also as you'd expect, hopefully).

I poked around a bit with the gcc vs. clang behavior, but wasn't able to trigger the compilation error; I'm assuming I didn't hit the right set of conditions to trigger it.

GCC always fails when you have a noexcept operator using default implementation, if any of the members operator used for default implementation is not noexcept. No matter if -fno-exception is set. But Clang will not throw those errors if -fno-exception is set.

In this case, I think GCC behavior is right: on code itself, using noexcept on an operator that requires parts that are noexcept is not allowed. It would work on Clang because -fno-exception is passed, but it is still invalid code. If we want to convert something to use noexcept, we really need to make sure it can be really noexcept. Ideally I would like Clang to also report that as an error, and that would definitely help with GCC-Clang compatibility.

Reply all
Reply to author
Forward
0 new messages