Skip to content

Commit ddcc3fc

Browse files
authored
Merge pull request #45 from jwnimmer-tri/testing-for-exceptions
Add some recent clarifications
2 parents edc9332 + 3138325 commit ddcc3fc

File tree

1 file changed

+92
-17
lines changed

1 file changed

+92
-17
lines changed

cppguide.html

Lines changed: 92 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2619,6 +2619,28 @@ <h3 id="Pass_By_Value">Pass by Value</h3>
26192619
<li><a href="https://stackoverflow.com/questions/10231349/are-the-days-of-passing-const-stdstring-as-a-parameter-over">Stack Overflow: Are the days of passing const std::string& as a parameter over?</a></li>
26202620
</ul>
26212621
</p>
2622+
2623+
<h4 id="Pass_By_Value_Primitives">Pass by Value: Primitives</h4>
2624+
2625+
<p>Prefer to pass primitives (e.g., <code>int</code> or <code>double</code>)
2626+
by value, not by const reference.</p>
2627+
2628+
<p>The same goes for copyable types that are tantamount to primitives,
2629+
such as type-safe integers (e.g., <code>drake::TypeSafeIndex</code> or
2630+
<code>drake::Identifier</code>) and thin wrappers
2631+
(e.g., <code>std::optional&lt;double&gt;</code>, because it's akin to a
2632+
pair of <code>(bool, double)</code>).
2633+
2634+
<p>Drake's
2635+
<a href="/doxygen_cxx/group__default__scalars.html">default scalars</a>
2636+
(known conventionally as <code>&lt;typename T&gt;</code>) are often thought
2637+
of as a <code>double</code> because they denote a mathematical scalar,
2638+
but because scalar types other than <code>double</code> are not primitives,
2639+
templated scalars should be passed as <code>const T&</code>, not by value.</p>
2640+
2641+
<p>See also <a href="#Use_of_const">Use of const</a> for an explanation of
2642+
whether arguments passed by-value may be declared <code>const</code>.</p>
2643+
26222644
</div>
26232645

26242646
<h3 id="Friends">Friends</h3>
@@ -2651,13 +2673,6 @@ <h3 id="Exceptions">Exceptions</h3>
26512673
noted below.</p>
26522674

26532675
<div class="stylebody">
2654-
<p class="drake">Unit tests may catch exceptions using
2655-
<a href="https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#exception-assertions">EXPECT_THROW</a>
2656-
or
2657-
<a href="https://github.com/RobotLocomotion/drake/blob/master/common/test_utilities/expect_throws_message.h">DRAKE_EXPECT_THROWS_MESSAGE</a>,
2658-
but only if the tested function's Doxygen documentation mentions that the
2659-
function throws an exception.</p>
2660-
26612676
<p class="drake">When documenting exceptions in an API, only state that
26622677
the function will throw <code>std::exception</code>; never promise a more
26632678
specific subclass:</p>
@@ -2667,11 +2682,28 @@ <h3 id="Exceptions">Exceptions</h3>
26672682
to refactor the code in ways that keeps the subclass unchanged.</li>
26682683
<li>There's no great way to deprecate a particular exception signature.</li>
26692684
<li>Since we can't catch exceptions anyway, nevermind use a multi-layer-catch
2670-
by specific subclasses, the only purpose of a subclass is for improved error
2671-
reporting -- this purpose is still met by throwing a subclass, but we don't
2672-
need to document it in Doxygen for this purpose.</li>
2685+
by specific subclasses, the only purpose of choosing a specific subclass is
2686+
for improved error reporting -- this purpose is still met by throwing a
2687+
subclass, but we don't need to document it in the API for this purpose.</li>
26732688
</ul>
2674-
</p>
2689+
2690+
<p class="drake">When throwing and there is no particular reason to choose
2691+
any particular subclass of <code>std::exception</code> to be thrown, prefer
2692+
to use <code>std::logic_error</code> as our nominal concrete type. The
2693+
clarity of the error message string matters more than the subtype choice.</p>
2694+
2695+
<p class="drake">Unit tests may catch exceptions using
2696+
<a href="https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#exception-assertions">EXPECT_THROW</a>
2697+
or
2698+
<a href="https://github.com/RobotLocomotion/drake/blob/master/common/test_utilities/expect_throws_message.h">DRAKE_EXPECT_THROWS_MESSAGE</a>:</p>
2699+
<ul class="drake">
2700+
<li>Only test for exceptions under the conditions where the tested function's
2701+
API documentation promises that the function throws an exception.</li>
2702+
<li>Only test for a specific subtype of <code>std::exception</code> when the
2703+
subtype is <em>necessary</em> to determine whether the code behaved correctly,
2704+
e.g., in cases where the code may throw several different types of exception
2705+
and the subtype fully disambiguates which condition was triggered. (This is
2706+
rare.)</li>
26752707
</div>
26762708

26772709
<p class="pros"></p>
@@ -4716,12 +4748,15 @@ <h3 id="General_Naming_Rules">General Naming Rules</h3>
47164748
variable names</a>.</p>
47174749

47184750
<p class="exception drake">
4719-
Method names may violate both the name structure standard and the “long,
4720-
human-readable” standard above if a short, non-compliant name more closely
4721-
matches the common conventions of the field. For instance, the matrix
4722-
portion of a linear complementarity constraint is traditionally ‘M’ (one
4723-
letter, upper-case); it is not mandatory to downcase it or give it a more
4724-
verbose name.
4751+
Variable and method names may violate both the capitalization standard and
4752+
the “long, human-readable” standard above if a short, non-compliant name
4753+
more closely matches the common conventions of the field. For instance, the
4754+
matrix portion of a linear complementarity constraint is traditionally ‘M’
4755+
(one letter, upper-case); it is not mandatory to downcase it or give it a
4756+
more verbose name. However, even if a variable name is capitalized to
4757+
match common conventions, we still use underscores ("snake case") to delimit
4758+
its words, not "camel case". For instance, <code>Ai_triplets</code> would
4759+
be the code spelling of the phrase “Aᵢ triplets”.
47254760
</p>
47264761
<p class="exception drake">
47274762
Note that the Drake multibody tree and related types have their own naming
@@ -4859,6 +4894,46 @@ <h3 id="Constant_Names">Constant Names</h3>
48594894
convention is optional for variables of other storage classes, e.g., automatic
48604895
variables, otherwise the usual variable naming rules apply.</p>
48614896

4897+
<div class="drake">
4898+
4899+
<p>Never use <code>kMixedCase</code> style for template arguments. In the
4900+
typical case, a template argument will refer to differing values within the
4901+
same program, so is not a program-wide constant.</p>
4902+
4903+
<pre>// OK - num_stages names to a value that is not a program-wide constant.
4904+
4905+
template &lt;typename T, int num_stages = 2&gt;
4906+
class RadauIntegrator { ... };
4907+
</pre>
4908+
4909+
<pre class="badcode">// BAD - kNumStages is not a program-wide constant.
4910+
4911+
template &lt;typename T, int kNumStages = 2&gt;
4912+
class RadauIntegrator { ... };
4913+
</pre>
4914+
4915+
<p>Even in the case of class data members (whether static or non-static),
4916+
never add a trailing underscore to a <code>kMixedCase</code> name.</p>
4917+
4918+
<pre>class Foo {
4919+
...
4920+
private:
4921+
const std::string default_name_{"name"}; // OK - snake_case_ member.
4922+
const std::string kDefaultName{"name"}; // OK - program-wide constant.
4923+
static const int kDefaultValue{1000}; // OK - static constant.
4924+
};
4925+
</pre>
4926+
4927+
<pre class="badcode">class Foo {
4928+
...
4929+
private:
4930+
const std::string kDefaultName_{"name"}; // Bad - underscore.
4931+
static const int kDefaultValue_{1000}; // Bad - underscore.
4932+
};
4933+
</pre>
4934+
4935+
</div>
4936+
48624937
<h3 id="Function_Names">Function Names</h3>
48634938

48644939
<p>Regular functions have mixed case; accessors and mutators may be named

0 commit comments

Comments
 (0)