Skip to content

Commit d5de2e4

Browse files
authored
Merge pull request #492 from manshreck/master
Export of internal doc changes to C++ Tips:
2 parents be41df8 + 4393c31 commit d5de2e4

File tree

4 files changed

+650
-5
lines changed

4 files changed

+650
-5
lines changed

_posts/2024-03-21-totw-224.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,9 @@ provably safe. The `at()` method is a bad approximation of this solution.
118118
Instead, we encourage users to stick with `operator[]` and reduce exposure to UB
119119
by other means, including:
120120

121-
* If your project can afford it, we recommend enabling bounds check in
122-
production using
123-
[HARDENING_ENABLE_SAFE_LIBCXX](http://go/cc_hardened_binary). Current
124-
measurements suggest the [macrobenchmark](https://abseil.io/fast/39) cost of
125-
this hardening is just barely statistically significant.
121+
* If your project can afford it, we recommend also enabling bounds check in
122+
production in other libraries where available.
123+
126124
* If you run your code with [ASAN][asan] you'll *also* get diagnostics if you
127125
access an element out of range.
128126

_posts/2024-09-30-totw-231.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
title: "Tip of the Week #231: Between Here and There: Some Minor Overlooked Algorithms"
3+
layout: tips
4+
sidenav: side-nav-tips.html
5+
published: true
6+
permalink: tips/231
7+
type: markdown
8+
order: "231"
9+
---
10+
11+
Originally posted as TotW #231 on March 7, 2024
12+
13+
*By [James Dennett](mailto:[email protected])*
14+
15+
Updated 2024-09-30
16+
17+
Quicklink: [abseil.io/tips/231](https://abseil.io/tips/231)
18+
19+
20+
## Overview
21+
22+
In recent C++ versions the Standard Library has added a few functions whose sole
23+
job is to supply some (specific!) point somewhere between two other points `x`
24+
and `y`: [`std::clamp`](https://en.cppreference.com/w/cpp/algorithm/clamp) (from
25+
C++17), and
26+
[`std::midpoint`](https://en.cppreference.com/w/cpp/numeric/midpoint) and
27+
[`std::lerp`](https://en.cppreference.com/w/cpp/numeric/lerp) (from C++20).
28+
29+
Adding these function templates to the Standard Library serves two main
30+
purposes. First, it establishes common terminology (vocabulary) for these
31+
operations, that is likely to be widely recognized. Second, and particularly in
32+
the case of `std::midpoint` and `std::lerp`, it ensures the availability of high
33+
quality implementations that
34+
[avoid common pitfalls](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0811r3.html).
35+
36+
All of these operations are `constexpr`, meaning that they can be used both at
37+
runtime and at compile time. The types that can be passed to them depend on the
38+
specific operation; they all support floating point types, and `std::midpoint`
39+
and `std::clamp` offer additional flexibility. Read on for the details.
40+
41+
### <code>std::clamp</code>
42+
43+
`std::clamp(x, min, max)` “clamps” x to the range [`min`, `max`]. More
44+
explicitly, if `x` is already in the range `min` to `max` (inclusive) then
45+
`std::clamp(x, min, max)` returns `x`, and for `x` outside of that range
46+
`std::clamp` returns whichever of `min` or `max` is closest to `x`. This is
47+
equivalent to `std::max(std::min(x, max), min)` except for being a more direct
48+
way to express the intent (and much less of a puzzle for readers).
49+
50+
> Warning: While `std::clamp` returns a *reference*, code depending on that is
51+
> subtle and unusual, and would warrant a comment to alert readers. It is easy
52+
> to accidentally create a dangling reference by passing a temporary to
53+
> `std::clamp` and binding the result to a temporary:
54+
>
55+
> <pre class="prettyprint lang-cpp bad-code">
56+
> // `std::clamp(1, 3, 4)` returns a reference to a temporary int initialized
57+
> // from `3`, which must not be used beyond the lifetime of the temporary.
58+
> // See [Tip #101](/tips/101).
59+
> const int& dangling = std::clamp(1, 3, 4);
60+
> </pre>
61+
62+
`std::clamp` works for any type that can be compared with `<` (or with a
63+
user-supplied comparator passed to `std::clamp(x, min, max, cmp`).
64+
65+
### <code>std::midpoint</code>
66+
67+
There are no surprises in what `std::midpoint` does: `std::midpoint(x, y)`
68+
returns a point halfway between `x` and `y` (rounding towards `x` when `x` and
69+
`y` are of an integral type).
70+
71+
`std::midpoint(x, y)` works for values `x`, `y` of any floating point or
72+
integral type (not including `bool`). As a bonus, `std::midpoint(p, q)` also
73+
works for pointers `p`, `q` into an array.
74+
75+
### <code>std::lerp</code>
76+
77+
The `lerp` in `std::lerp` is short for “linear interpolation”, and `std::lerp(x,
78+
y, t)` returns a value some fraction `t` of the way from `x` to `y`. For
79+
example, `std::lerp(x, y, 0)` returns `x`, `std::lerp(x, y, 1)` returns y, and
80+
`std::lerp(x, y, 0.5)` can be simplified to `std::midpoint(x, y)`.
81+
82+
Note: In spite of the name, `std::lerp` can also be used for extrapolation if we
83+
pass a value of `t` outside of the range `[0, 1]`. For example, `std::lerp(100,
84+
101, -2)` evaluates to 98, and `std::lerp(100, 101, +2)` is 102.
85+
86+
`std::lerp` works on floating point types.
87+
88+
## Recommendations
89+
90+
1. One of the main benefits of these library functions is that they provide a
91+
common vocabulary. As always, prefer to use these standard facilities
92+
instead of writing them from scratch.
93+
1. Prefer `std::midpoint(x, y)` over `std::lerp(x, y, 0.5)` when applicable.
94+
1. Avoid declaring a reference to the result of `std::clamp`.

_posts/2024-09-30-totw-232.md

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
---
2+
title: "Tip of the Week #232: When to Use <code>auto</code> for Variable Declarations"
3+
layout: tips
4+
sidenav: side-nav-tips.html
5+
published: true
6+
permalink: tips/232
7+
type: markdown
8+
order: "232"
9+
---
10+
11+
Originally posted as TotW #232 on June 20, 2024
12+
13+
*By [Kenji Inoue](mailto:[email protected]) and Michael Diamond, Google Engineer*
14+
15+
Updated 2024-09-30
16+
17+
Quicklink: [abseil.io/tips/232](https://abseil.io/tips/232)
18+
19+
20+
The style guide says in the
21+
[Type Deduction (including auto)](https://google.github.io/styleguide/cppguide.html#Type_deduction)
22+
section:
23+
24+
> Use type deduction only if it makes the code clearer to readers who aren't
25+
> familiar with the project, or if it makes the code safer. Do not use it merely
26+
> to avoid the inconvenience of writing an explicit type.
27+
28+
Ironically, overuse of `auto` often leads to code becoming less clear. Over
29+
time, however, several patterns have emerged where using `auto` can improve code
30+
clarity and safety, such as:
31+
32+
* In situations where specifying the type correctly can be difficult and
33+
specifying the wrong type can lead to performance or correctness issues,
34+
e.g., range-based `for` loops over a map.
35+
* In situations where the type information is truly redundant and
36+
specification of the full type is distracting, e.g., commonly-used templated
37+
factory functions and some iterator uses.
38+
* In generic code where the type itself is not important as long as it is
39+
syntactically correct.
40+
41+
We'll discuss each of those cases below, with an eye toward clarifying the cases
42+
in which `auto` makes code safer or clearer.
43+
44+
## Range-Based For Loops Over a Map
45+
46+
The following code has a problem that each element in the map is unintentionally
47+
copied:
48+
49+
<pre class="prettyprint lang-cpp bad-code">
50+
absl::flat_hash_map&lt;std::string, DogBreed&gt; dog_breeds_by_name = ...;
51+
// `name_and_breed` is copy-constructed for each element of the map.
52+
for (const std::pair&lt;std::string, DogBreed&gt;& name_and_breed :
53+
dog_breeds_by_name) {
54+
...
55+
}
56+
</pre>
57+
58+
The unintended copy happens because the `value_type` of associative containers
59+
is `std::pair<const Key, Value>` and `std::pair` allows implicit conversions
60+
between pair objects if their underlying types can be implicitly converted.
61+
Because `std::pair::first_type` here is `std::string` and the map entry here has
62+
`std::pair::first_type` of `const std::string`, the pairs are not the same type
63+
and an implicit conversion occurs, copying the contents of the pair despite
64+
`name_and_breed` being declared as a reference.
65+
66+
Using `auto`, possibly in conjunction with structured bindings
67+
([Tip #169](/tips/169)), can make the code safer and more performant:
68+
69+
<pre class="prettyprint lang-cpp code">
70+
absl::flat_hash_map&lt;std::string, DogBreed&gt; dog_breeds_by_name = ...;
71+
72+
// `auto` with structured bindings - if the element types are clear from local
73+
// context.
74+
for (const auto& [name, breed] : dog_breeds_by_name) {
75+
...
76+
}
77+
</pre>
78+
79+
Sometimes, the element types are not obvious from local context. In that case,
80+
you can do this:
81+
82+
<pre class="prettyprint lang-cpp code">
83+
// `auto` without structured bindings - allows specifying the element types.
84+
for (const auto& name_and_breed : dog_breeds_by_name) {
85+
const std::string& name = name_and_breed.first;
86+
const DogBreed& breed = name_and_breed.second;
87+
...
88+
}
89+
</pre>
90+
91+
## Iterators
92+
93+
The names of iterator types are verbose and often provide redundant type
94+
information when the type of the container is visible nearby.
95+
96+
Here is an example code snippet that assigns an iterator to a local variable.
97+
98+
<pre class="prettyprint lang-cpp code">
99+
std::vector&lt;std::string&gt; names = ...;
100+
std::vector&lt;std::string&gt;::iterator name_it = names.begin();
101+
while (name_it != names.end()) {
102+
...
103+
}
104+
</pre>
105+
106+
All containers expose `begin()` and `end()` functions which return iterators,
107+
and these iterators have type `ContainerType::iterator` or
108+
`ContainerType::const_iterator`.
109+
110+
When the type of the container is visible nearby, calling out these types would
111+
only have a small benefit of differentiating `iterator` and `const_iterator`
112+
because the container type part (e.g., `std::vector<std::string>`) is the same
113+
as that of the container. In this case, we can use `auto` to remove redundancy
114+
without hiding helpful information:
115+
116+
<pre class="prettyprint lang-cpp code">
117+
std::vector&lt;std::string&gt; names = ...;
118+
auto name_it = names.begin();
119+
while (name_it != names.end()) {
120+
...
121+
}
122+
</pre>
123+
124+
When the container type is not visible locally, prefer to spell out the full
125+
iterator type or element type:
126+
127+
<pre class="prettyprint lang-cpp code">
128+
std::vector&lt;std::string&gt;::iterator name_it = names_.begin();
129+
while (name_it != names_.end()) {
130+
...
131+
}
132+
</pre>
133+
134+
<pre class="prettyprint lang-cpp code">
135+
auto name_it = names_.begin();
136+
while (name_it != names_.end()) {
137+
const std::string& name = *name_it;
138+
...
139+
}
140+
</pre>
141+
142+
## <code>std::make_unique</code> and Other Google-wide Factory Functions
143+
144+
In the following code snippet, `std::make_unique` and
145+
`proto2::MakeArenaSafeUnique` specify the types to be instantiated.
146+
147+
<pre class="prettyprint lang-cpp code">
148+
std::unique_ptr&lt;MyFavoriteType&gt; my_type =
149+
std::make_unique&lt;MyFavoriteType&gt;(...);
150+
151+
proto2::ArenaSafeUniquePtr&lt;MyFavoriteProto&gt; my_proto =
152+
proto2::MakeArenaSafeUnique&lt;MyFavoriteProto&gt;(arena);
153+
</pre>
154+
155+
It is widely known throughout Google that `std::make_unique<T>` returns
156+
`std::unique_ptr<T>` and `proto2::MakeArenaSafeUnique<T>` returns
157+
`proto2::ArenaSafeUniquePtr<T>`. In particular, the important part of the
158+
resulting type `T` is specified on the right-hand side (RHS) expression, and it
159+
is company-wide knowledge rather than project-specific knowledge. We can use
160+
`auto` here to remove redundancy without hiding helpful information:
161+
162+
<pre class="prettyprint lang-cpp code">
163+
auto my_type = std::make_unique&lt;MyFavoriteType&gt;(...);
164+
165+
auto my_proto = proto2::MakeArenaSafeUnique&lt;MyFavoriteProto&gt;(arena);
166+
</pre>
167+
168+
## Generic Code
169+
170+
In some circumstances when writing generic code, such as templates or GoogleTest
171+
matchers, the type may be impossible or very difficult to specify (e.g., a type
172+
written with template metaprogramming or `decltype`). In these cases `auto` may
173+
also be appropriate. However, these situations should be rare.
174+
175+
## Otherwise: Avoid Using <code>auto</code>
176+
177+
While it can be tempting to use `auto` in situations where the type is long and
178+
seems obvious to *you*, remember that future readers of the code may not be
179+
familiar with your project and the types it uses
180+
([why](http://go/readability#why)). For example, consider a common pattern of
181+
nested proto access.
182+
183+
<pre class="prettyprint lang-cpp bad-code">
184+
// Of course `breed` has type `const DetailedDomesticCatBreed&`!
185+
const auto& breed = cat.pedigree().detailed_breed();
186+
</pre>
187+
188+
`auto` may also hide basic semantics like constness, whether a type is a
189+
pointer, and whether a copy is being made ([Tip #44](/tips/44)).
190+
191+
<pre class="prettyprint lang-cpp bad-code">
192+
// Did the author mean to make a copy here?
193+
// It is not obvious to all readers that `breed` is not a reference even though
194+
// `detailed_breed()` returns a reference!
195+
auto breed = cat.pedigree().detailed_breed();
196+
</pre>
197+
198+
<pre class="prettyprint lang-cpp code">
199+
// Type and semantics are clear.
200+
const DetailedDomesticCatBreed& breed = cat.pedigree().detailed_breed();
201+
</pre>
202+
203+
## Summary of Recommendations
204+
205+
* Use `auto` when manually writing out a more specific type would incur a high
206+
risk of correctness or performance problems.
207+
* Use `auto` to remove redundancy without hiding helpful information when the
208+
useful type information is visible locally.
209+
* For some generic code where the type is impossible or very difficult to
210+
specify, `auto` may be appropriate; these situations should be rare.
211+
* **Avoid using `auto` in other situations**: while it may make it easier for
212+
you to write the code or allow you to avoid a line-break, it probably makes
213+
the code harder to understand for someone unfamiliar with your project.
214+
215+
## See Also
216+
217+
* https://google.github.io/styleguide/cppguide.html#auto for the authoritative
218+
guidance
219+
* [Tip #4](/tips/4): Tip of the Week #4: Automatic for the People
220+
* [Tip #44](/tips/44): Tip of the Week #44: Qualifying auto

0 commit comments

Comments
 (0)