Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project import generated by Copybara. #475

Merged
merged 1 commit into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions _posts/2018-02-22-totw-93.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ Some of the benefits of using `Span` as a function parameter are similar to
those of using `string_view`.

The caller can pass a slice of the original vector, or pass a plain array. It is
also compatible with other array-like containers, like `InlinedVector`,
`FixedArray`, `google::protobuf::RepeatedField`, etc.
also compatible with other array-like containers, like `absl::InlinedVector`,
`absl::FixedArray`, `google::protobuf::RepeatedField`, etc.

As with `string_view`, it is usually better to pass `Span` by value when used as
a function parameter - this form is slightly faster, and produces smaller code.
Expand Down
2 changes: 1 addition & 1 deletion _posts/2018-05-03-totw-148.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ order: "148"

Originally posted as TotW #148 on May 3, 2018

*By [Titus Winters](mailto:titus@google.com)*
*By [Titus Winters](mailto:titus@cs.ucr.edu)*

Updated 2020-04-06

Expand Down
6 changes: 3 additions & 3 deletions _posts/2018-05-03-totw-149.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ order: "149"

Originally posted as TotW #149 on May 3, 2018

*By [Titus Winters](mailto:titus@google.com)*
*By [Titus Winters](mailto:titus@cs.ucr.edu)*

Updated 2020-04-06

Expand Down Expand Up @@ -188,8 +188,8 @@ expressed in those types, not in the APIs that operate on them.
### Ref-qualification

As a side note: it's possible to apply the same reasoning for ref-qualifiers on
destructive accessors. Consider a class like `std::stringbuf` - in C++20 it will
gain an accessor to consume the contained string, presented as an overload set
destructive accessors. Consider a class like `std::stringbuf` - in C++20 it
gained an accessor to consume the contained string, presented as an overload set
with the existing accessor:

<pre class="prettyprint lang-cpp code">
Expand Down
6 changes: 6 additions & 0 deletions _posts/2018-09-28-totw-144.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,5 +134,11 @@ types require explicit opt-in from the user.
The [B-Tree][btree] containers (`absl::btree_{set,map,multiset,multimap}`) also
support heterogeneous lookup.

[Protocol Buffers'](protobuf) associative map's implementation,
`google::protobuf::Map`, supports heterogeneous lookup when the map is keyed
with `std::string` using string-like keys (any type that is convertible to
`absl::string_view`).

[swisstables]: https://abseil.io/docs/cpp/guides/container
[btree]: https://abseil.io/docs/cpp/guides/container
[protobuf]: https://protobuf.dev/
2 changes: 1 addition & 1 deletion _posts/2019-10-01-totw-180.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ order: "180"

Originally posted as TotW #180 on June 11, 2020

*By [Titus Winters](mailto:titus@google.com)*
*By [Titus Winters](mailto:titus@cs.ucr.edu)*

Updated 2020-06-11

Expand Down
45 changes: 36 additions & 9 deletions _posts/2019-12-12-totw-146.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ uninitialized is not trivial.
The first thing to understand is if the type under construction is scalar,
aggregate, or some other type. A *scalar* type can be thought of as a simple
type: an integral or floating point arithmetic object; a pointer; an enum; a
pointer-to-member; `nullptr_t`. An *aggregate* type is an array or trivial class
(one with only public, non-static data members, no user-provided constructors,
no base classes, and no virtual member functions).
pointer-to-member; `nullptr_t`. An *aggregate* type is an array or a class with
nothing virtual, no non-public fields or bases, and no constructor declarations.

Another factor affecting whether an instance has been initialized to a value
that is safe to read is whether it has an explicit *initializer*. That is, the
Expand Down Expand Up @@ -81,6 +80,33 @@ constructor, so `default_foo.v` is also zero-initialized and is safe to read.
Note that `Foo::s` has a user-provided constructor, so it is value-initialized
in either case, and safe to read.

## User-Declared vs User-Provided Constructors

It is possible for the user to *declare* a constructor while asking the compiler
to *provide* the definition via `=default`. For example:

<pre class="prettyprint lang-cpp code">
struct Foo {
Foo() = default; // "Used-declared", NOT "user-provided".

int v;
};

int main() {
Foo default_foo;
Foo value_foo = {};
}
</pre>

In this case, `Foo` defines a *user-declared*, but not *user-provided*,
constructor. While this type will not be an aggregate, members will be
initialized as if for an aggregate. This means that `default_foo.v` will be
uninitialized, while `value_foo.v` will be *zero-initialized*. Note that
"user-declared" only applies to a default constructor which is defaulted (`=
default`) *at its point of declaration*. A defaulted out-of-line
*implementation* (`Foo::Foo() = default`) is considered user-provided and will
behave equivalently to a definition of `Foo::Foo() {}`.

### Uninitialized Members in User-Provided Constructors

<pre class="prettyprint lang-cpp code">
Expand Down Expand Up @@ -195,13 +221,14 @@ Many developers would reasonably assume that this may affect code generation
quality, but otherwise is a style preference. As you might have guessed, because
I'm asking, this is not the case.

The reason goes back to the first section above on User-provided Constructors.
The reason goes back to the section above on
[User-Declared vs User-Provided Constructors](#user-declared-vs-user-provided-constructors).
As the constructor for `Foo` is defaulted on declaration, it is not
user-provided. This means that `Foo` is an aggregate type, and `f.v` is
zero-initialized. However, `Bar` has a user-provided constructor, albeit created
by the compiler as a defaulted constructor. As this constructor does not
explicitly initialize `Bar::v`, `b.v` will be default-initialized and unsafe to
read.
user-provided (but it *is* user-declared). This means that while `Foo` is not an
aggregate type, `f.v` is still zero-initialized. However, `Bar` has a
user-provided constructor, albeit created by the compiler as a defaulted
constructor. As this constructor does not explicitly initialize `Bar::v`, `b.v`
will be default-initialized and unsafe to read.

## Recommendations

Expand Down
12 changes: 6 additions & 6 deletions _posts/2019-12-12-totw-166.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ Updated 2020-04-06
Quicklink: [abseil.io/tips/166](https://abseil.io/tips/166)


*Entia non sunt multiplicanda praeter necessitatem." ("Entities should not be
*"Entia non sunt multiplicanda praeter necessitatem." ("Entities should not be
multiplied without necessity") -- William of Ockham*

*If you don't know where you're going, you're probably going wrong. -- Terry
*"If you don't know where you're going, you're probably going wrong." -- Terry
Pratchett*

## Overview
Expand Down Expand Up @@ -60,10 +60,10 @@ In practice, however, the object was always constructed "in place" in the
variable `thing`, with no moves being performed, and the C++ language rules
permitted these move operations to be "elided" to facilitate this optimization.

In C++17, this code is guaranteed to perform zero copies or moves. In fact, the
above code is valid even if `BigExpensiveThing` is not moveable. The constructor
call in `BigExpensiveThing::Make` directly constructs the local variable `thing`
in `UseTheThing`.
Since C++17, this code is guaranteed to perform zero copies or moves. In fact,
the above code is valid even if `BigExpensiveThing` is not moveable. The
constructor call in `BigExpensiveThing::Make` directly constructs the local
variable `thing` in `UseTheThing`.

So what's going on?

Expand Down
26 changes: 13 additions & 13 deletions _posts/2019-12-19-totw-108.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,17 @@ std::bind(&MyClass::OnDone, this, std::placeholders::_1)
</pre>

Ugh, that's ugly. Is there a better way? Why yes, use
[`absl::bind_front()`](https://github.com/abseil/abseil-cpp/blob/master/absl/functional/bind_front.h)
instead.
[`std::bind_front()`](https://en.cppreference.com/w/cpp/utility/functional/bind_front)
instead. (For code that cannot yet use C++20, there's `absl::bind_front`.)

<pre class="prettyprint lang-cpp code">
absl::bind_front(&MyClass::OnDone, this)
std::bind_front(&MyClass::OnDone, this)
</pre>

Remember partial function application -- the thing that `std::bind()` *does not
do*? Well, `absl::bind_front()` does exactly that: it binds the first N
arguments and perfect-forwards the rest: `absl::bind_front(F, a, b)(x, y)`
evaluates to `F(a, b, x, y)`.
do*? Well, `std::bind_front()` does exactly that: it binds the first N arguments
and perfect-forwards the rest: `std::bind_front(F, a, b)(x, y)` evaluates to
`F(a, b, x, y)`.

Ahhh, sanity is restored. Want to see something truly terrifying now? What does
this code do?
Expand Down Expand Up @@ -107,7 +107,7 @@ void ProcessAsync(std::unique_ptr&lt;Request&gt; req) {
Good old passing `std::unique_ptr` across async boundaries. Needless to say,
`std::bind()` isn't a solution -- the code doesn't compile, because
`std::bind()` doesn't move the bound move-only argument to the target function.
Simply replacing `std::bind()` with `absl::bind_front()` fixes it.
Simply replacing `std::bind()` with `std::bind_front()` fixes it.

The next example regularly trips even C++ experts. See if you can find the
problem.
Expand Down Expand Up @@ -139,7 +139,7 @@ which case it evaluates to `F(arg())`. If `arg` is converted to

**Applying std::bind() to a type you don't control is always a bug**.
`DoStuffAsync()` shouldn't apply `std::bind()` to the template argument. Either
`absl::bind_front()` or lambda would work fine.
`std::bind_front()` or lambda would work fine.

The author of `DoStuffAsync()` might even have entirely green tests because they
always pass a lambda or `std::function` as the argument but never the result of
Expand Down Expand Up @@ -167,7 +167,7 @@ vs
</pre>

**Calls to std::bind() that perform partial application are better off as
absl::bind_front().** The more placeholders you have, the more obvious it gets.
std::bind_front().** The more placeholders you have, the more obvious it gets.

<pre class="prettyprint lang-cpp code">
std::bind(&MyClass::OnDone, this, std::placeholders::_1)
Expand All @@ -176,11 +176,11 @@ std::bind(&MyClass::OnDone, this, std::placeholders::_1)
vs

<pre class="prettyprint lang-cpp code">
absl::bind_front(&MyClass::OnDone, this)
std::bind_front(&MyClass::OnDone, this)
</pre>

(Whether to use `absl::bind_front()` or a lambda when performing partial
function application is a judgement call; use your discretion.)
(Whether to use `std::bind_front()` or a lambda when performing partial function
application is a judgement call; use your discretion.)

This covers 99% of all calls `std::bind()`. The remaining calls do something
fancy:
Expand All @@ -197,7 +197,7 @@ of a few characters or lines of code are worth it.

### Conclusion

Avoid `std::bind`. Use a lambda or `absl::bind_front` instead.
Avoid `std::bind`. Use a lambda or `std::bind_front` instead.

### Further Reading

Expand Down
15 changes: 8 additions & 7 deletions _posts/2020-04-06-totw-163.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ void MyFunc(std::optional&lt;Foo&gt; foo);

Otherwise, skip the `std::optional` altogether.

You can pass it by `const Foo*` and let `nullptr` indicate "does not exist."
You can pass it by `absl::Nullable<const Foo*>` and let `nullptr` indicate "does
not exist."

<pre class="prettyprint lang-cpp code">
void MyFunc(const Foo* foo);
void MyFunc(absl::Nullable&lt;const Foo*&gt; foo);
</pre>

This will be just as efficient as passing by `const Foo&`, but supports null
Expand All @@ -80,10 +81,10 @@ class members and function return values often work well with `std::optional`.

### Exception

If you expect all callers of your function to already have an object inside of
an `std::optional`, then you may take a `const std::optional&`. However, this is
rare; it usually only occurs if your function is private within your own
file/library.
If you expect all callers of your function to already have a
`std::optional<Foo>` and never pass in a `Foo`, then you may take a `const
std::optional<Foo>&`. However, this is rare; it usually only occurs if your
function is private within your own file/library.

### What about <code>std::reference_wrapper</code>?

Expand All @@ -102,4 +103,4 @@ However, we don't recommend this:
the standard library special case it in ways that make it act differently
from a normal value or reference.
* `std::optional<std::reference_wrapper<const Foo>>` is cumbersome and
verbose, compared to simply `const Foo*`.
verbose, compared to `absl::Nullable<const Foo*>`.
4 changes: 2 additions & 2 deletions _posts/2020-04-06-totw-172.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ Quicklink: [abseil.io/tips/172](https://abseil.io/tips/172)


[Designated initializers](https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers)
are a syntax in the draft C++20 standard for specifying the contents of a struct
in a compact yet readable and maintainable manner. Instead of the repetitive
are a syntax in the C++20 standard for specifying the contents of a struct in a
compact yet readable and maintainable manner. Instead of the repetitive

<pre class="prettyprint lang-cpp code">
struct Point {
Expand Down
2 changes: 1 addition & 1 deletion _posts/2020-04-06-totw-173.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ class DoublePrinter {
But then if you need to allow the option struct to be skipped entirely, such as
when it's being added to an existing class, and the nested struct has a default
member initializer (the `= 8` after the field name `precision`, for example),
you cannot use have a
you cannot have a
[default argument](https://google.github.io/styleguide/cppguide.html#Default_Arguments)
whose value leaves the field implicit.

Expand Down
10 changes: 8 additions & 2 deletions _posts/2020-04-06-totw-175.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,14 @@ hex digits are present).
Hex floating point literals are indicated by writing a `p` (or `P`) to separate
the significand from the exponent—where decimal floating point literals would
use `e` (or `E`). For example, `0x2Ap12` is another way to write the value `0x2A
<< 12`, i.e., 0x2A000. The exponent is always written in decimal, denotes a
power of 2, and may be negative: `0x1p-10` is (exactly) `1.0/1024`.
<< 12`, i.e., 0x2A000, except that is a floating point value, not an integer. As
a result, our style guide
[requires](https://google.github.io/styleguide/cppguide.html#Floating_Literals)
it to be written as `0x2A.0p12` to be explicit that it is a floating point value
and not just another way to write an integer.

The exponent is always written in decimal, denotes a power of 2, and may be
negative: `0x1p-10` is (exactly) `1.0/1024`.

## Recommendations

Expand Down
2 changes: 1 addition & 1 deletion _posts/2020-04-06-totw-176.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ composable; that is, it can easily be used as part of a wider expression, e.g.
consistent with the
[style guide](https://google.github.io/styleguide/cppguide.html#Output_Parameters).
- **Use generic wrappers** like `std::optional` to represent a missing return
value. Consider returning `absl::variant`if you need a more flexible
value. Consider returning `std::variant`if you need a more flexible
representation with multiple alternatives.
- **Use a struct** to return multiple values from a function.
- Feel free to write a new struct specifically to represent the return
Expand Down
2 changes: 1 addition & 1 deletion _posts/2020-04-06-totw-177.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ order: "177"

Originally posted as TotW #177 on April 6, 2020

*By [Titus Winters](mailto:titus@google.com)*
*By [Titus Winters](mailto:titus@cs.ucr.edu)*

Updated 2020-04-06

Expand Down
Loading
Loading