{"id":870,"date":"2024-02-02T19:45:13","date_gmt":"2024-02-02T19:45:13","guid":{"rendered":"http:\/\/int03.co.uk\/blog\/?p=870"},"modified":"2024-02-02T20:25:44","modified_gmt":"2024-02-02T20:25:44","slug":"c-17-if-statement-gotchas","status":"publish","type":"post","link":"https:\/\/int03.co.uk\/blog\/2024\/02\/02\/c-17-if-statement-gotchas\/","title":{"rendered":"C++ 17 if statement gotchas"},"content":{"rendered":"\n<p>C++17 added a useful extension to the if-statement syntax, by making it possible to include initialisation inside the if-statement. This is called &#8220;if statement with initializer&#8221;. You can use it like this:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(16px, 1rem, 24px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"if (int spuds = getNumberOfSpuds()) {\n    bakeSpuds(spuds);\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">int<\/span><span style=\"color: #D4D4D4\"> spuds = <\/span><span style=\"color: #DCDCAA\">getNumberOfSpuds<\/span><span style=\"color: #D4D4D4\">()) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">bakeSpuds<\/span><span style=\"color: #D4D4D4\">(spuds);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Providing spuds != 0 it will obligingly bake them for us (in fact, it will even bake negative spuds&#8230; very handy in the current financial climate). Better yet, you can also add a condition, like this:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(16px, 1rem, 24px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"if (int spuds = getNumberOfSpuds(); spuds &gt; 10) {\n    std::cout << &quot;we have plenty of spuds&quot; << std::endl;\n} \" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">int<\/span><span style=\"color: #D4D4D4\"> spuds = <\/span><span style=\"color: #DCDCAA\">getNumberOfSpuds<\/span><span style=\"color: #D4D4D4\">(); spuds &gt; <\/span><span style=\"color: #B5CEA8\">10<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::cout &lt;&lt; <\/span><span style=\"color: #CE9178\">&quot;we have plenty of spuds&quot;<\/span><span style=\"color: #D4D4D4\"> &lt;&lt; <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::endl;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">} <\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>This is often used to check pointers before dereferencing them:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(16px, 1rem, 24px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"if (auto* car = getCar()) {\n    car-&gt;setHandbrake(true);\n    car-&gt;setSteeringAngle(70.f);\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\">* car = <\/span><span style=\"color: #DCDCAA\">getCar<\/span><span style=\"color: #D4D4D4\">()) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">car<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #DCDCAA\">setHandbrake<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">true<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">car<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #DCDCAA\">setSteeringAngle<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #B5CEA8\">70.f<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Obviously these are very useful features, as it brings the variable instantiation into the scope of the if-statement and makes for neater code. We love it and use it a lot!<\/p>\n\n\n\n<p>Unfortunately, this also seems to have led to a common misconception in how the condition can be used. In working on some fairly large C++ projects, we found quite a few instances of this type of code:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(16px, 1rem, 24px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"if (auto* car = getCar(); car-&gt;hasWheels()) {\n    \/\/ DANGER: if car is nullptr, will dereference nullptr\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\">* car = <\/span><span style=\"color: #DCDCAA\">getCar<\/span><span style=\"color: #D4D4D4\">(); <\/span><span style=\"color: #9CDCFE\">car<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #DCDCAA\">hasWheels<\/span><span style=\"color: #D4D4D4\">()) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">    \/\/ DANGER: if car is nullptr, will dereference nullptr<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>The intent of this code is obvious: the developer clearly expected it to only execute the condition if car != nullptr. Essentially, they <em>expected <\/em>it to check that car != nullptr, then execute the condition, and only enter the if-statement if car is valid, and the car has wheels. However, it doesn&#8217;t work like that. It will always execute the condition and will dereference the car pointer, regardless of whether it is nullptr or not, so this code is quite likely to <strong>crash<\/strong>.<\/p>\n\n\n\n<p>Usually this is fairly easily fixed by doing something like this:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(16px, 1rem, 24px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"if (auto* car = getCar(); car &amp;&amp; car-&gt;hasWheels()) {\n    std::cout << &quot;we have a car, and it has wheels&quot; << std::endl;\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\">* car = <\/span><span style=\"color: #DCDCAA\">getCar<\/span><span style=\"color: #D4D4D4\">(); car &amp;&amp; <\/span><span style=\"color: #9CDCFE\">car<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #DCDCAA\">hasWheels<\/span><span style=\"color: #D4D4D4\">()) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::cout &lt;&lt; <\/span><span style=\"color: #CE9178\">&quot;we have a car, and it has wheels&quot;<\/span><span style=\"color: #D4D4D4\"> &lt;&lt; <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::endl;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>But the really nasty thing about buggy code like this is that it can often <em>appear <\/em>to work fine, until one day it blows up. This can lead to really nasty intermittent bugs, which are exceedingly hard to debug. Worse still, static code analysis tools might not spot this issue, and we had obviously missed some of these in code reviews also. If you suspect bugs like this are present, it&#8217;s also quite hard to grep your code base to find them. For example: searching for lines containing &#8220;if&#8221; and a semicolon will bring up a huge number of hits, which have to be searched manually. This makes it especially important not to introduce them in the first place \ud83d\ude42<\/p>\n\n\n\n<p>Here&#8217;s an example of some such code which appears to work (at least, it doesn&#8217;t crash), but is obviously not correct:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(16px, 1rem, 24px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"struct Car {\n    bool hasWheels() {\n        return true;\n    }\n};\n\nCar* nullCar = nullptr;\n\nif (auto* car = nullCar) {\n    std::cout << &quot;we have a car&quot; << std::endl;\n}\n\nif (auto* car = nullCar; car-&gt;hasWheels()) {\n    std::cout << &quot;car has wheels&quot; << std::endl;\n    \/\/ Spoiler: this may be a lie\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">struct<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Car<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">bool<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">hasWheels<\/span><span style=\"color: #D4D4D4\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">true<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">Car* nullCar = <\/span><span style=\"color: #569CD6\">nullptr<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\">* car = nullCar) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::cout &lt;&lt; <\/span><span style=\"color: #CE9178\">&quot;we have a car&quot;<\/span><span style=\"color: #D4D4D4\"> &lt;&lt; <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::endl;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\">* car = nullCar; <\/span><span style=\"color: #9CDCFE\">car<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #DCDCAA\">hasWheels<\/span><span style=\"color: #D4D4D4\">()) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::cout &lt;&lt; <\/span><span style=\"color: #CE9178\">&quot;car has wheels&quot;<\/span><span style=\"color: #D4D4D4\"> &lt;&lt; <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::endl;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">    \/\/ Spoiler: this may be a lie<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>If you run this, it <strong>won&#8217;t<\/strong> output &#8220;we have a car&#8221;, but it probably <strong>will<\/strong> output &#8220;car has wheels&#8221;, even though car is nullptr. It does that because hasWheels is just returning a constant value, so the compiler doesn&#8217;t actually need to use our pointer. Although this is a somewhat contrived example (because our function could have been static, and we are using raw pointers etc), I hope it illustrates the point: that just because code appears to work when you test it, that doesn&#8217;t necessarily prove the code is correct.<\/p>\n\n\n\n<p>Another misconception I&#8217;ve seen in practice is when people put initialisation in both the initialisation and condition, assuming that the compiler will check both conditions (it doesn&#8217;t):<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(16px, 1rem, 24px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"if (auto* foo = getFoo(); auto* bar = getBar()) {\n    \/\/ DANGER: if foo == nullptr and bar != nullptr\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\">* foo = <\/span><span style=\"color: #DCDCAA\">getFoo<\/span><span style=\"color: #D4D4D4\">(); <\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\">* bar = <\/span><span style=\"color: #DCDCAA\">getBar<\/span><span style=\"color: #D4D4D4\">()) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">    \/\/ DANGER: if foo == nullptr and bar != nullptr<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>It will enter the if statement if bar != nullptr, even if foo == nullptr. For example, this code would result in a nullptr dereference, because it only cares whether the condition on the right hand side is true, and doesn&#8217;t care whether car is nullptr or not:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:clamp(16px, 1rem, 24px);font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:clamp(20px, 1.25rem, 30px);--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"if (auto* car = nullptr; auto* driver = new Driver) {\n    \/\/ DANGER: if car == nullptr, it will dereference the nullptr\n    car-&gt;setDriver(driver);\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\">* car = <\/span><span style=\"color: #569CD6\">nullptr<\/span><span style=\"color: #D4D4D4\">; <\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\">* driver = <\/span><span style=\"color: #C586C0\">new<\/span><span style=\"color: #D4D4D4\"> Driver) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">    \/\/ DANGER: if car == nullptr, it will dereference the nullptr<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">car<\/span><span style=\"color: #D4D4D4\">-&gt;<\/span><span style=\"color: #DCDCAA\">setDriver<\/span><span style=\"color: #D4D4D4\">(driver);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>It&#8217;s worth saying that this code wasn&#8217;t introduced by inexperienced C++ developers. In fact, some of it was written by very capable, experienced and knowledgeable C++ developers, some with many years of experience. It just goes to show how easy it is to slip up and introduce this kind of bug. I suspect this is a fairly common issue, and something that it is useful to be aware of.<\/p>\n\n\n\n<p>Finally, if you want to search for this kind of issue in a large code base, it is somewhat possible by using regular expressions. For example, in Visual Studio&#8217;s &#8220;Find in Files&#8221; option, you can select &#8220;Use regular expressions&#8221;. To find lines that contain both &#8220;if&#8221; and a semicolon you can do something like this:<\/p>\n\n\n\n<p><code><mark style=\"background-color:#ffe5d1\" class=\"has-inline-color\">if.*;<\/mark><\/code><\/p>\n\n\n\n<p>This expression should find lines that contain &#8220;if&#8221; and a semicolon, but the semicolon can&#8217;t be at the end of the line:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code><mark style=\"background-color:#ffe5d1\" class=\"has-inline-color\">\\bif\\b.*;(?!\\s*$)<\/mark><\/code><\/code><\/pre>\n\n\n\n<p>Don&#8217;t ask me about regular expressions, because I am no expert &#8211; just sharing one that worked for me \ud83d\ude42<\/p>\n\n\n\n<p>Either way, this will bring up a fairly long list of search results that you will have to sift through manually. All the more reason to take care not to introduce them in the first place&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>C++17 added a useful extension to the if-statement syntax, by making it possible to include initialisation inside the if-statement. This is called &#8220;if statement with initializer&#8221;. You can use it like this: Providing spuds != 0 it will obligingly bake them for us (in fact, it will even bake negative spuds&#8230; very handy in the &hellip; <a href=\"https:\/\/int03.co.uk\/blog\/2024\/02\/02\/c-17-if-statement-gotchas\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">C++ 17 if statement gotchas<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/int03.co.uk\/blog\/wp-json\/wp\/v2\/posts\/870"}],"collection":[{"href":"https:\/\/int03.co.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/int03.co.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/int03.co.uk\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/int03.co.uk\/blog\/wp-json\/wp\/v2\/comments?post=870"}],"version-history":[{"count":12,"href":"https:\/\/int03.co.uk\/blog\/wp-json\/wp\/v2\/posts\/870\/revisions"}],"predecessor-version":[{"id":885,"href":"https:\/\/int03.co.uk\/blog\/wp-json\/wp\/v2\/posts\/870\/revisions\/885"}],"wp:attachment":[{"href":"https:\/\/int03.co.uk\/blog\/wp-json\/wp\/v2\/media?parent=870"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/int03.co.uk\/blog\/wp-json\/wp\/v2\/categories?post=870"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/int03.co.uk\/blog\/wp-json\/wp\/v2\/tags?post=870"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}