Skip to content

Commit

Permalink
Project import generated by Copybara.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 618258885
Change-Id: I8782cc9206b935ab84bc65f7adaf39b5641a95a3
  • Loading branch information
Abseil Team authored and manshreck committed Mar 22, 2024
1 parent 10385b8 commit e3feacf
Show file tree
Hide file tree
Showing 24 changed files with 814 additions and 131 deletions.
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

0 comments on commit e3feacf

Please sign in to comment.