{"id":334,"date":"2014-09-08T15:15:20","date_gmt":"2014-09-08T19:15:20","guid":{"rendered":"http:\/\/blog.mozilla.org\/nfroyd\/?p=334"},"modified":"2014-09-08T15:15:20","modified_gmt":"2014-09-08T19:15:20","slug":"xpcom-and-move-constructors","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/nfroyd\/2014\/09\/08\/xpcom-and-move-constructors\/","title":{"rendered":"xpcom and move constructors"},"content":{"rendered":"<p>Benjamin Smedberg <a href=\"https:\/\/groups.google.com\/d\/msg\/mozilla.dev.platform\/QJOFokGkE1Y\/e132tcuvAR0J\">recently announced that he was handing over XPCOM module ownership duties<\/a> to me.\u00a0 XPCOM contains basic data structures used throughout the Mozilla codebase, so changes to its code can have wide-ranging effects.\u00a0 I&#8217;m honored to have been given responsibility for a core piece of the Gecko platform.<\/p>\n<p>One issue that&#8217;s come up recently and I&#8217;m sure will continue to come up is changing XPCOM data structures to support two new C++11 features, rvalue references and their killer app, move constructors.\u00a0 If you aren&#8217;t familiar with C++11&#8217;s new rvalue references feature, I highly recommend <a href=\"http:\/\/thbecker.net\/articles\/rvalue_references\/section_01.html\">C++ Rvalue References Explained<\/a>.\u00a0 Move constructors are already being put to good use elsewhere in the codebase, notably <tt><a href=\"http:\/\/whereswalden.com\/2014\/07\/31\/mfbt-now-has-uniqueptr-and-makeunique-for-managing-singly-owned-resources\/\">mozilla::UniquePtr<\/a><\/tt>, which can be used to replace XPCOM&#8217;s <tt>nsAutoPtr<\/tt> and <tt>nsAutoRef<\/tt> (<a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1055035\">bug 1055035<\/a>).\u00a0 And some XPCOM data structures have received the move constructor treatment, notably <tt>nsRefPtr<\/tt> (<a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=980753\">bug 980753<\/a>) and <tt>nsTArray<\/tt> (<a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=982212\">bug 982212<\/a>).<\/p>\n<p>A <a href=\"https:\/\/groups.google.com\/forum\/#!topic\/mozilla.dev.platform\/ffXWJaMo7Ig\">recent discussion<\/a> and <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1015114\">the associated bug<\/a>, however, decided that the core referenced-counted smart pointer class in XPCOM, <tt>nsCOMPtr<\/tt>, shouldn&#8217;t support move constructors.\u00a0 While move constructors could have replaced the <tt>already_AddRefed<\/tt> usage associated with <tt>nsCOMPtr<\/tt>, such as:<\/p>\n<pre>already_AddRefed&lt;nsIMyInterface&gt;\r\nNS_DoSomething(...)\r\n{\r\n  nsCOMPtr&lt;nsIMyInterface&gt; interface = ...;\r\n  \/\/ do some initialization stuff\r\n  return interface.forget();\r\n}<\/pre>\n<p>with the slightly shorter:<\/p>\n<pre>nsCOMPtr&lt;nsIMyInterface&gt;\r\nNS_DoSomething(...)\r\n{\r\n  nsCOMPtr&lt;nsIMyInterface&gt; interface = ...;\r\n  \/\/ do some initialization stuff\r\n  return interface;\r\n}<\/pre>\n<p>There were two primary arguments against move constructor support.\u00a0 The first argument was that the explicitness of having to call <tt>.forget()<\/tt> on an <tt>nsCOMPtr<\/tt> (along with the explicitness of the <tt>already_AddRefed<\/tt> type), rather than returning it, is valuable for the code author, the patch reviewer, and subsequent readers of the code.\u00a0 When dealing with ownership issues in C++, it pays to be more explicit, rather than less.\u00a0 The second argument was that due to the implicit conversion of <tt>nsCOMPtr&lt;T&gt;<\/tt> to a bare <tt>T*<\/tt> pointer (a common pattern in smart pointer classes), returning <tt>nsCOMPtr&lt;T&gt;<\/tt> from functions makes it potentially easy to write buggy code:<\/p>\n<pre>\/\/ What really happens in the below piece of code is something like:\r\n\/\/\r\n\/\/ nsIMyInterface* p;\r\n\/\/ {\r\n\/\/   nsCOMPtr&lt;nsIMyInterface&gt; tmp(NS_DoSomething(...));\r\n\/\/   p = tmp.get();\r\n\/\/ }\r\n\/\/\r\n\/\/ which is bad if NS_DoSomething is returning the only ref to the object.\r\n\/\/ p now points to deleted memory, which is a security risk.\r\nnsIMyInterface* p = NS_DoSomething(...);<\/pre>\n<p>(I should note that we can return <tt>nsCOMPtr&lt;T&gt;<\/tt> from functions today, and in most cases, thanks to <a href=\"http:\/\/en.wikipedia.org\/wiki\/Return_value_optimization\">compiler optimizations<\/a>, it will be as efficient as returning <tt>already_AddRefed<\/tt>.\u00a0 But Gecko culture is such that a function returning <tt>nsCOMPtr&lt;T&gt;<\/tt> would be quite unusual, and therefore unlikely to pass code review.)<\/p>\n<p>The changes to add move constructors to <tt>nsRefPtr<\/tt> and <tt>nsTArray<\/tt>?\u00a0 They were reviewed by me.\u00a0 And the nixing of move constructors for <tt>nsCOMPtr<\/tt>?\u00a0 That was also done by me (with a lot of feedback from other people).<\/p>\n<p>I accept the charge of inconsistency.\u00a0 However, I offer the following defense.\u00a0 In the case of <tt>nsTArray<\/tt>, there are no ownership issues like there are with <tt>nsCOMPtr<\/tt>: you either own the array, or you don&#8217;t, so many of the issues raised about <tt>nsCOMPtr<\/tt> don&#8217;t apply in that case.<\/p>\n<p>For the case of <tt>nsRefPtr<\/tt>, it is true that I didn&#8217;t seek out as much input from other people before approving the patch.\u00a0 But the <tt>nsRefPtr<\/tt> patch was also done without the explicit goal of removing <tt>already_AddRefed<\/tt> from the code base, which made it both smaller in scope and more palatable.\u00a0 Also, my hunch is that <tt>nsRefPtr<\/tt> is used somewhat less than <tt>nsCOMPtr<\/tt> (although this may be changing somewhat given other improvements in the codebase, like WebIDL), and so it provides an interesting testbed for whether move constructors and\/or less explicit transfers of ownership are as much of a problem as argued above.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Benjamin Smedberg recently announced that he was handing over XPCOM module ownership duties to me.\u00a0 XPCOM contains basic data structures used throughout the Mozilla codebase, so changes to its code can have wide-ranging effects.\u00a0 I&#8217;m honored to have been given responsibility for a core piece of the Gecko platform. One issue that&#8217;s come up recently [&hellip;]<\/p>\n","protected":false},"author":320,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[540,72421],"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/posts\/334"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/users\/320"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/comments?post=334"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/posts\/334\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/media?parent=334"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/categories?post=334"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/tags?post=334"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}