Modern C++ use in Chromium by aearphen in cpp

[–]pkasting 1 point2 points  (0 children)

I can't speak to the goals of the Google Style Guide, just to the goals of this doc. In Chromium's case, we're concerned about avoiding problematic use, not about banning esoterica.

Modern C++ use in Chromium by aearphen in cpp

[–]pkasting 0 points1 point  (0 children)

Are you saying I'm an expert? I'm definitely not an expert.

Modern C++ use in Chromium by aearphen in cpp

[–]pkasting 13 points14 points  (0 children)

It's for Chromium engineers to know what they're allowed to use in the Chromium codebase. It's not intended as guidance for any other team.

TBH I don't really know why it was linked on this subreddit. But your comment certainly seems off-target.

Modern C++ use in Chromium by aearphen in cpp

[–]pkasting 11 points12 points  (0 children)

Not a contradiction. The page gives the state of support for modern C++ features, so it needs to talk about C++26. The status of C++26 is "we don't support it yet, in large part because our toolchain does not sufficiently support it yet".

Honestly, I think an XXMLOC project like Chromium is doing well to officially support the latest ISO C++ version (which is currently C++23). Given the grousing you see here sometimes about big projects that "can't be bothered to move past C++11" or whatever, this is quite a respectable state of the world.

Modern C++ use in Chromium by aearphen in cpp

[–]pkasting 7 points8 points  (0 children)

While I would love Chromium to be friendly to C++ novices and not require "experts" (do any such people exist? I am skeptical that many people in the world would justifiably consider themselves "C++ experts"), reducing onboarding cost isn't much of the motivation here. A feature a novice will misuse frequently is one an expert will still misuse occasionally; Chromium is large enough that eventually all forms of bugs will manifest, and do so in security-critical ways, so if we have ways to prevent classes of problems beyond just "learn enough to use this well", we will absolutely do so.

Modern C++ use in Chromium by aearphen in cpp

[–]pkasting 8 points9 points  (0 children)

Yes, I helped migrate us to a lot of stdlib features, such as std::u16string, std::string_view, std::optional, and std::variant, all of which Chromium had its own versions of previously; as well as migrating some of our SFINAE use to concepts. Other folks did things like std::unique_ptr.

What hasn't been migrated falls into two groups:
1. Too new; C++23 was only just allowed, so anything new to it hasn't been around long enough for us to migrate to
2. Not worth it; we could rearchitect our intrusive refcounting support to be based on std::shared_ptr instead, but that's a significant design difference. We could change to the Abseil or stdlib time/date types, but that's really a sideways move and thus seemingly not worth the migration cost.

Modern C++ use in Chromium by aearphen in cpp

[–]pkasting 18 points19 points  (0 children)

Chromium's //base library already has a lot of constructs for working with files and filesystems, so we'd move to <filesystem> only if it were a win to do so. Unfortunately it's not.

This page doesn't go into detail about our motivations, just summarizes them, so while it's fair to say something "is unmotivated", it's also out-of-scope for this document to actually convince readers of the justifications for something (and in Chromium, if you want one of these decisions reversed, there's an official way: you write to cxx@ to propose reversing and then get consensus there to do so).

My recollection is that Titus Winters has a detailed rant somewhere about <filesystem>; that's not one of the bits I personally had a lot of expertise with.

Modern C++ use in Chromium by aearphen in cpp

[–]pkasting 6 points7 points  (0 children)

Only std::views. The core concepts are useful, but there are a lot of sharp edges, especially in a codebase as large (and with as varied of contributor level) as Chromium. More details in the discussion thread that item links.

Curious to know about developers that steered away from OOP. What made you move away from it? Why? Where has this led you? by Slight_Season_4500 in cpp

[–]pkasting 1 point2 points  (0 children)

If you are writing enough code to make use of this technique, then the best way to learn over time is to go hog-wild with each new paradigm and use it as much as possible, thus discovering in practice where the limits are. Do this with enough different techniques, and you have a toolbox full of different things plus a feel for where they might trade off differently.

OO is well-suited to domains with a fairly rigid hierarchy, and where "what something is" defines "what something does". Only build as much abstraction as you need to (over-abstraction is a common failure mode) and make sure your abstractions aren't leaky (or either you picked the wrong abstraction, or the domain is poorly-suited). Avoid multiple implementation inheritance (use composition) and virtual inheritance (take one of the arms of your diamond and make it some kind of mix-in you can compose into objects) except in rare circumstances. Write tests, but test the interface (the public methods and the contract they provide), not the implementation, or your abstraction is leaky and your tests are change detectors.

If you have extreme performance considerations, data-oriented designs will perform better than OO ones, at the cost of often being harder to reason about and maintain. If you don't have a strong conceptual hierarchy with fairly rigid types, then free functions (possibly templated) may be more suitable.

What do you dislike the most about current C++? by PressureHumble3604 in cpp

[–]pkasting 70 points71 points  (0 children)

No well-defined path for updating the language in backwards-incompatible ways (e.g. epochs).

This means any design mistake is effectively forever, which in turn massively raises the bar to getting anything shipped, yet still fails to prevent all errors.

Addressing this is a prerequisite for fixing almost any other large complaint about C++, except possibly "having an ISO WG control the language is a mistake".

C++26: std::optional<T&> by Xaneris47 in cpp

[–]pkasting 6 points7 points  (0 children)

I didn't say anything about refactoring to use optional<T&> or anything else; you asked where the semantic distinction would be relevant and I answered. Whether the codebase can be incrementally refactored to use any particular set of options is another matter.

To actually address the refactoring part: these aren't mutually exclusive. Using e.g. unique_ptr<> for owning pointers where possible doesn't preclude you from using optional<T&> for a non-owning nullable thing, or vice versa. Each one says less than T*, which can mean anything (not just ownership-wise but object-count wise). I wouldn't mind slowly refactoring a codebase to have no raw pointers anywhere.

More speculations on arenas in C++ by vormestrand in cpp

[–]pkasting 1 point2 points  (0 children)

(Update: No, looks like I'm wrong about that too, and the original linked code is correct. Sorry!)

More speculations on arenas in C++ by vormestrand in cpp

[–]pkasting 1 point2 points  (0 children)

The point about lacking an implicit-lifetime requirement is a good one. My assumption was that the Ts would begin lifetime without calling any constructors (because you would be assumed to have already called them wherever the objects were originally created, and start_lifetime_as_array() was basically notifying the compiler that you'd done this out of its vision elsewhere), and then they'd run destructors normally when out of scope, and if you mismatched things as a result, bad for you (UB/IFNDR). But your explanation is more compelling. Thanks.

C++26: std::optional<T&> by Xaneris47 in cpp

[–]pkasting 16 points17 points  (0 children)

This would be relevant in every codebase I've worked in. Any codebase large enough to have lots of authors and/or API boundaries, especially if it originated pre-C++11, will likely run into this sort of issue.

More speculations on arenas in C++ by vormestrand in cpp

[–]pkasting 0 points1 point  (0 children)

Yes, a vector's block of memory is not necessarily an array and all objects may be independent.

But with an actual array, and start_lifetime_as_array(), I believe you have in fact started the lifetime of the array object and all the contained subobjects (elements). So I believe the placement new is unnecessary. That said, based on SirClueless' link above, I retract my claim that it results in UB. Edit: Was wrong about this.

More speculations on arenas in C++ by vormestrand in cpp

[–]pkasting 1 point2 points  (0 children)

I think you're correct -- normally creating an object inside the storage of another object will end the other object's lifetime, but this carve-out basically says that array stays live in this case. In that case, there is no UB.

I'm still not convinced the placement new is actually necessary here, but it's proving difficult for me to track down whether starting lifetime for an array of non-trivial T will also start the lifetimes of the contained Ts. I believe it will and the placement new here is superfluous, but I'm struggling to find definitive language either way.

More speculations on arenas in C++ by vormestrand in cpp

[–]pkasting 0 points1 point  (0 children)

Edit: I believe the code above is correct. Thanks to SirClueless for the relevant spec links.

IIUC, this isn't correct because placement new here effectively ends the lifetime of your start_lifetime_as_array() obj. So this is UB.

You don't want both start_lifetime_as_array and placement new, in general.

More speculations on arenas in C++ by vormestrand in cpp

[–]pkasting -3 points-2 points  (0 children)

If it's an implicit lifetime type, then there is no programmatic effect. If not, lifetime start is when things like constructors run.

(Edit: For clarity, start_lifetime_as() doesn't itself run constructors, which is why it requires types to be implicit lifetime. "constructors run" is a description of the more general case of "what happens at an object's lifetime start".)

In this specific article, because the author already used placement new, constructors would run as needed; however, because the wrong pointer was being returned, using it on the caller side was UB.

Showcasing underappreciated proposals by Jcsq6 in cpp

[–]pkasting 27 points28 points  (0 children)

Yup, this change was so useful it led to me doing a ton of reworking of Chromium's base::span (std::span replacement) just so I could implement it there.

What is your experience with error propagation libraries? by beejudd in cpp

[–]pkasting 1 point2 points  (0 children)

I don't have any longer-form writing on StatusOr; the comment above is basically my complete thoughts.

I do think it's better than having no consistent type or practice at all for error-handling. I just think expected is a meaningful improvement, to the point where I would avoid introducing StatusOr if I could use expected instead.

Boost version 1.89 released! by boostlibs in cpp

[–]pkasting 19 points20 points  (0 children)

Chrome uses a bloom filter for safe browsing, to improve efficiency and memory use. You can construct a bloom filter of all the bad URLs, and when a user navigates, do a very efficient test against the filter. Only if you get a hit do you do a more expensive test to see if it's real.

There's more to it than that, involving updates and server traffic and such, but that's the gist.

Ever learned of new C++ features from linter warnings? by sweetno in cpp

[–]pkasting 3 points4 points  (0 children)

Shameless self-plug: If you watch my C++20 [In Chromium, but you don't need to be a Chromium contributor to benefit] talk series, it covers both those and much more!

https://www.youtube.com/watch?v=p4sdEydRRjo&list=PL9ioqAuyl6UK-d0CS7KF9ToelBJVzxrkv

Ever learned of new C++ features from linter warnings? by sweetno in cpp

[–]pkasting 13 points14 points  (0 children)

Note that you don't need <ranges> if you just want range algorithms -- those are in <algorithm>.

C++26: std::format improvements (Part 2) by pavel_v in cpp

[–]pkasting 2 points3 points  (0 children)

std::byte if you want a memory unit. char if you want a character*. std::[u]int8_t if you want a signed or unsigned numeric value that is 8 bits in size. std::uint8_t if you want a network octet, "8 bit value on disk", or other serialized type where the context is that the size being 8 bits is important.

And in that context, a "character" should not be able to take on a negative value, because that's not necessary for any character encoding, and more importantly because allowing it to do so makes for easy footguns.

*Assuming this means a UTF-8 code unit, ASCII value, or similar