{"id":106438,"date":"2022-04-08T07:00:00","date_gmt":"2022-04-08T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106438"},"modified":"2022-04-11T16:14:17","modified_gmt":"2022-04-11T23:14:17","slug":"20220408-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220408-00\/?p=106438","title":{"rendered":"Please repeat yourself: The <CODE>noexcept(noexcept(&#8230;))<\/CODE> idiom"},"content":{"rendered":"<p>Consider the following class:<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct Holder\r\n{\r\n    T value;\r\n\r\n    template&lt;typename... Args&gt;\r\n    Holder(Args&amp;&amp;... args) :\r\n        value(std::forward&lt;Args&gt;(args)...) {}\r\n};\r\n\r\ntemplate&lt;typename U&gt; Holder(U&amp;&amp;) -&gt;\r\n    Holder&lt;std::remove_reference_t&lt;U&gt;&gt;\r\n<\/pre>\n<p>The idea is that this class holds a value of type <code>T<\/code>, and it constructs the same way that a <code>T<\/code> does. (The deduction guide lets you write <code>Holder(42)<\/code> instead of <code>Holder&lt;int&gt;(42)<\/code>.)<\/p>\n<p>Now the question: Is the object nothrow constructible?<\/p>\n<p>Nothrow constructibility is important for various operations. For example, a prerequisite for the strong exception guarantee for many operations is that the objects involved be nothrow-copyable or nothrow-movable. And internally, the standard library contains optimizations which are activated if the types involved are nothrow-operable.<\/p>\n<p>Back to the question: Is the object nothrow constructible?<\/p>\n<p>No, this object&#8217;s constructor is potentially-throwing because it lacks a <code>noexcept<\/code> specifier. This is true even though the construction of the <code>T<\/code> from the <code>args...<\/code> may itself be noexcept.<\/p>\n<p>What we want is for our constructor to be noexcept precisely when the construction of the underlying <code>T<\/code> is noexcept. How can we do that?<\/p>\n<p>The <code>noexcept<\/code> specifier takes an optional compile-time <code>bool<\/code> parameter which indicates whether the function is non-throwing, and the parameter defaults to <code>true<\/code>, which is what you&#8217;re doing when you write a bare <code>noexcept<\/code>.<\/p>\n<p>Here&#8217;s the first column of the last table in my discussion of <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180928-00\/?p=99855\"> the sad history of the C++ <code>throw()<\/code> exception specifier<\/a>:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th colspan=\"2\">Specifier<br \/>\nC++17<\/th>\n<\/tr>\n<tr>\n<td style=\"vertical-align: middle; width: 2em;\" rowspan=\"2\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">Nonthrowing<\/span><\/td>\n<td><code>noexcept<\/code><br \/>\n<code>noexcept(true)<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>throw()<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"vertical-align: middle; width: 2em;\" rowspan=\"2\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">Throwing<\/span><\/td>\n<td><code>noexcept(false)<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>throw(something)<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>So we can make our constructor conditionally-<code>noexcept<\/code> by putting an appropriate expression inside the parentheses. But what is the correct expression?<\/p>\n<p>The <code>noexcept<\/code> keyword has another purpose: You can use it as an operator in an expression, and it evaluates to <code>true<\/code> if the evaluation of the argument would be considered non-throwing by the compiler. Like <code>sizeof<\/code>, the argument itself is not evaluated.<\/p>\n<pre>bool example1 = noexcept(1 + 2); \/\/ true\r\nbool example2 = noexcept(1 \/ 0); \/\/ true\r\n\r\nbool example3 = noexcept(\r\n    std::declval&lt;std::string&gt;().clear()); \/\/ true\r\nbool example4 = noexcept(\r\n    std::declval&lt;std::string&gt;().resize(0)); \/\/ false\r\n<\/pre>\n<p>The first example is simple: We can add 1 and 2, and there will not be a C++ exception.<\/p>\n<p>The second example is a little trickier: The compiler says that dividing by zero will not raise a C++ exception. Now, dividing by zero is actually undefined behavior, but the compiler isn&#8217;t performing any division here. It&#8217;s just checking whether <code>operator\/(int, int)<\/code> is potentially-throwing, and it is not.<\/p>\n<p>The third example highlights that the inner expression is not evaluated. We are using the <code>std::declval&lt;T&gt;<\/code> function which pretends to return a <code>T<\/code>, although you are not allowed to actually call it. It may be used only in unevaluated contexts.<\/p>\n<p>The fourth example is a bit interesting: Although resizing a string to zero is functionally equivalent to clearing it, it has a different exception specifier, because the <code>resize()<\/code> method may throw if asked to make a string bigger and it cannot allocate memory for the bigger string.<\/p>\n<p>When the <code>noexcept(...)<\/code> operator is determining whether an expression is potentially-throwing, the compiler looks only at what&#8217;s printed on the tin.<\/p>\n<p>We can now combine these two lesser-used parts of the <code>noexcept<\/code> keyword. We want our constructor to be conditionally <code>noexcept<\/code> based on whether the inner <code>value<\/code>&#8216;s constructor is potentially-throwing given the forwarded <code>args...<\/code>.<\/p>\n<p>Whether the <code>T<\/code> constructor is potentially-throwing given the forwarded <code>args...<\/code> can be calculated by asking the <code>noexcept(...)<\/code> operator to pretend to construct it, and report whether the result is potentially-throwing.<\/p>\n<pre>noexcept(T(std::forward&lt;Args&gt;(args)...))\r\n<\/pre>\n<p>The result of that calculation is then fed to the <code>noexcept<\/code> specifier to tell it whether the <code>Holder<\/code> constructor, given those arguments, should also be considered potentially-throwing.<\/p>\n<pre>noexcept(noexcept(T(std::forward&lt;Args&gt;(args)...)))\r\n<\/pre>\n<p>The outer <code>noexcept<\/code> is an exception specifier, but the inner one is a <code>noexcept<\/code> operator. The C++ language is reluctant to introduce new language keywords for fear of breaking existing code that used those potential keywords as identifiers, so it prefers to reuse existing keywords in new ways.\u00b9<\/p>\n<pre>    template&lt;typename... Args&gt;\r\n    Holder(Args&amp;&amp;... args)\r\n        <span style=\"color: blue;\">noexcept(noexcept(T(std::forward&lt;Args&gt;(args)...)))<\/span> :\r\n        value(std::forward&lt;Args&gt;(args)...) {}\r\n<\/pre>\n<p>We want our constructor to have the same potentially-throwing behavior as the construction of <code>value<\/code>, so we use the repetitive <code>noexcept(noexcept(...))<\/code> idiom to say &#8220;I&#8217;m noexcept if that guy is&#8221;, and &#8220;that guy&#8221; is itself a repetition of the thing we&#8217;re actually going to do one line later.<\/p>\n<p>The <code>noexcept(noexcept(...))<\/code> idiom could be <a href=\"https:\/\/en.wikipedia.org\/wiki\/Don't_repeat_yourself\"> pejoratively<\/a> called the &#8220;Please repeat yourself twice&#8221; idiom. You have to repeat the keyword <code>noexcept<\/code>, and you also have to repeat the expression whose potentially-throwing behavior you want to propagate.<\/p>\n<p><b>Bonus reading<\/b>: <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-the-noexcept-specifier-and-operator\"> C++ Core Guidelines: The noexcept Specifier and Operator<\/a><\/p>\n<p>\u00b9 We saw this in C++11, which took the long-forgotten <code>auto<\/code> keyword and gave it a brand new life.\u00b2<\/p>\n<p>\u00b2 I&#8217;m eagerly awaiting the triumphant return of the <code>register<\/code> keyword, which like <code>auto<\/code> has been reserved since K&amp;R C, but had been largely abandoned, and which was formally stripped of all meaning in C++17.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Each time you say it, it means something different.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-106438","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Each time you say it, it means something different.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106438","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=106438"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106438\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=106438"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106438"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106438"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}