{"id":5076,"date":"2014-03-30T18:39:59","date_gmt":"2014-03-30T18:39:59","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2014\/03\/30\/how-does-the-compiler-benefit-from-cs-new-final-keyword-collection-of-common-programming-errors\/"},"modified":"2014-03-30T18:39:59","modified_gmt":"2014-03-30T18:39:59","slug":"how-does-the-compiler-benefit-from-cs-new-final-keyword-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2014\/03\/30\/how-does-the-compiler-benefit-from-cs-new-final-keyword-collection-of-common-programming-errors\/","title":{"rendered":"How does the compiler benefit from C++&#39;s new final keyword?-Collection of common programming errors"},"content":{"rendered":"<p>Virtual calls to functions are slightly more costly that normal calls. In addition to actually performing the call, the runtime must first determine which function to call, which oftens leads to:<\/p>\n<ol>\n<li>Locating the v-table pointer, and through it reaching the v-table<\/li>\n<li>Locating the function pointer within the v-table, and through it performing the call<\/li>\n<\/ol>\n<p>Compared to a direct call where the address of the function is known in advance (and hard-coded with a symbol), this leads to a small overhead. Good compilers manage to make it only 10%-15% slower than a regular call, which is usually insignificant if the function has any meat.<\/p>\n<p>A compiler&#8217;s optimizer still seeks to avoid all kinds of overhead, and <strong>devirtualizing<\/strong> function calls is generally a low-hanging fruit. For example, see in C++03:<\/p>\n<pre><code>struct Base { virtual ~Base(); };\n\nstruct Derived: Base { virtual ~Derived(); };\n\nvoid foo() {\n  Derived d; (void)d;\n}\n<\/code><\/pre>\n<p>Clang gets:<\/p>\n<pre><code>define void @foo()() {\n  ; Allocate and initialize `d`\n  %d = alloca i8**, align 8\n  %tmpcast = bitcast i8*** %d to %struct.Derived*\n  store i8** getelementptr inbounds ([4 x i8*]* @vtable for Derived, i64 0, i64 2), i8*** %d, align 8\n\n  ; Call `d`'s destructor\n  call void @Derived::~Derived()(%struct.Derived* %tmpcast)\n\n  ret void\n}\n<\/code><\/pre>\n<p>As you can see, the compiler was already smart enough to determine that <code>d<\/code> being a <code>Derived<\/code> then it is unnecessary to incur the overhead of virtual call.<\/p>\n<p>In fact, it would optimize the following function just as nicely:<\/p>\n<pre><code>void bar() {\n  Base* b = new Derived();\n  delete b;\n}\n<\/code><\/pre>\n<p>However there are some situations where the compiler cannot reach this conclusion:<\/p>\n<pre><code>Derived* newDerived();\n\nvoid deleteDerived(Derived* d) { delete d; }\n<\/code><\/pre>\n<p>Here we could expect (naively) that a call to <code>deleteDerived(newDerived());<\/code> would result in the same code than before. However it is not the case:<\/p>\n<pre><code>define void @foobar()() {\n  %1 = tail call %struct.Derived* @newDerived()()\n  %2 = icmp eq %struct.Derived* %1, null\n  br i1 %2, label %_Z13deleteDerivedP7Derived.exit, label %3\n\n; :3                                       ; preds = %0\n  %4 = bitcast %struct.Derived* %1 to void (%struct.Derived*)***\n  %5 = load void (%struct.Derived*)*** %4, align 8\n  %6 = getelementptr inbounds void (%struct.Derived*)** %5, i64 1\n  %7 = load void (%struct.Derived*)** %6, align 8\n  tail call void %7(%struct.Derived* %1)\n  br label %_Z13deleteDerivedP7Derived.exit\n\n_Z13deleteDerivedP7Derived.exit:                  ; preds = %3, %0\n  ret void\n}\n<\/code><\/pre>\n<p>Convention could dictate that <code>newDerived<\/code> returns a <code>Derived<\/code>, but the compiler cannot make such an assumption: and what if it returned something further derived ? And thus you get to see all the ugly machinery involved in retrieving the v-table pointer, selecting the appropriate entry in the table and finally performing the call.<\/p>\n<p>If however we put a <code>final<\/code> in, then we give the compiler a guarantee that it cannot be anything else:<\/p>\n<pre><code>define void @deleteDerived2(Derived2*)(%struct.Derived2* %d) {\n  %1 = icmp eq %struct.Derived2* %d, null\n  br i1 %1, label %4, label %2\n\n; :2                                       ; preds = %0\n  %3 = bitcast i8* %1 to %struct.Derived2*\n  tail call void @Derived2::~Derived2()(%struct.Derived2* %3)\n  br label %4\n\n; :4                                      ; preds = %2, %0\n  ret void\n}\n<\/code><\/pre>\n<p>In short: <code>final<\/code> allows the compiler to avoid the overhead of virtual calls for the concerned functions in situations where detecting it is impossible.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Virtual calls to functions are slightly more costly that normal calls. In addition to actually performing the call, the runtime must first determine which function to call, which oftens leads to: Locating the v-table pointer, and through it reaching the v-table Locating the function pointer within the v-table, and through it performing the call Compared [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5076","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/5076","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=5076"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/5076\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=5076"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=5076"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=5076"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}