{"id":27503,"date":"2007-03-26T10:00:00","date_gmt":"2007-03-26T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2007\/03\/26\/passing-by-address-versus-passing-by-reference-a-puzzle\/"},"modified":"2007-03-26T10:00:00","modified_gmt":"2007-03-26T10:00:00","slug":"passing-by-address-versus-passing-by-reference-a-puzzle","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20070326-00\/?p=27503","title":{"rendered":"Passing by address versus passing by reference, a puzzle"},"content":{"rendered":"<p>\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/pages\/407234.aspx#410239\">\nCommenter Mike Petry asked<\/a> via the Suggestion Box:\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nWhy can you dereference a COM interface pointer and pass it\nto a function with a Com interface reference.\n<\/p>\n<p>\nThe call.\n<\/p>\n<pre>\nOutputDebugString(_T(\"IntfByRef::Execute - Begin\\n\"));\nBadBoy badone;\nCComPtr&lt;IDoer&gt; Doer;\nDoer.CoCreateInstance(CLSID_Doer, NULL, CLSCTX_INPROC_SERVER);\n\/\/ created a raw pointer - maybe the\n\/\/ smart pointer was effecting it some how.\nIDoer* Doer2;\nDoer.CopyTo(&amp;Doer2);\nbadone.stupid_method(*Doer2);\nDoer2-&gt;Release();\n\/\/ no still works.\n<\/pre>\n<p>\nThe function called.\n<\/p>\n<pre>\nvoid stupid_method(IDoer&amp; IDoerRef)\n{\n IDoerRef.Do();\n CComQIPtr&lt;IDispatch&gt; WatchIt(&amp;IDoerRef);\n if( WatchIt )\n  OutputDebugString(_T(\"QI the address of the \")\n                    _T(\"ref works - this is weird\\n\"));\n else\n  OutputDebugString(_T(\"At least trying to QI the \")\n                    _T(\"address of the ref fails\\n\"));\n}\n<\/pre>\n<p>\nI found some code written like this during a code review.\nIt is wrong but it seems to work.\n<\/p>\n<\/blockquote>\n<p>\nYou already know the answer to this question.\nYou merely got distracted by the use of a COM interface.\nLet me rephrase the question, using an abstract C++ class\ninstead of a COM interface.\n(The virtualness isn&#8217;t important to the discussion.)\nGiven this code:\n<\/p>\n<pre>\nclass Doer {\n public: virtual void Do() = 0;\n};\nvoid caller(Doer *p)\n{\n stupid_method(*p);\n}\nvoid stupid_method(Doer&amp; ref)\n{\n ref.Do();\n}\n<\/pre>\n<p>\nHow is this different from the pointer version?\n<\/p>\n<pre>\nvoid caller2(Doer *p)\n{\n stupid_method2(p);\n}\nvoid stupid_method2(Doer *p)\n{\n p-&gt;Do();\n}\n<\/pre>\n<p>\nThe answer:\nFrom the compiler&#8217;s point of view, it&#8217;s the same.\nI could prove this by going into what references mean,\nbut you&#8217;d just find that boring,\nbut instead I&#8217;ll show you the generated code.\nFirst, the version that passes by reference:\n<\/p>\n<pre>\n; void caller(Doer *p) { stupid_method(*p); }\n  00000 55               push    ebp\n  00001 8b ec            mov     ebp, esp\n  00003 ff 75 08         push    DWORD PTR _p$[ebp]\n  00006 e8 00 00 00 00   call    stupid_method\n  0000b 5d               pop     ebp\n  0000c c2 04 00         ret     4\n; void stupid_method(Doer&amp; ref) { ref.Do(); }\n  00000 55               push    ebp\n  00001 8b ec            mov     ebp, esp\n  00003 8b 4d 08         mov     ecx, DWORD PTR _ref$[ebp]\n  00006 8b 01            mov     eax, DWORD PTR [ecx]\n  00008 ff 10            call    DWORD PTR [eax]\n  0000a 5d               pop     ebp\n  0000b c2 04 00         ret     4\n<\/pre>\n<p>\nNow the version that passes by address:\n<\/p>\n<pre>\n; void caller2(Doer *p) { stupid_method2(p); }\n  00000 55               push    ebp\n  00001 8b ec            mov     ebp, esp\n  00003 ff 75 08         push    DWORD PTR _p$[ebp]\n  00006 e8 00 00 00 00   call    stupid_method2\n  0000b 5d               pop     ebp\n  0000c c2 04 00         ret     4\n; void stupid_method2(Doer *p) { p-&gt;Do(); }\n  00000 55               push    ebp\n  00001 8b ec            mov     ebp, esp\n  00003 8b 4d 08         mov     ecx, DWORD PTR _p$[ebp]\n  00006 8b 01            mov     eax, DWORD PTR [ecx]\n  00008 ff 10            call    DWORD PTR [eax]\n  0000a 5d               pop     ebp\n  0000b c2 04 00         ret     4\n<\/pre>\n<p>\nNotice that the code generation is identical.\n<\/p>\n<p>\nIf you&#8217;re still baffled, go ask your local C++ expert.\n<\/p>\n<p>\nMind you, dereferencing an abstract object is highly unusual\nand will probably cause the people who read your code to\nscratch their heads, but it is nevertheless technically legal,\nin the same way it is technically legal to give a function\nthat deletes an item the name <code>add_item<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Commenter Mike Petry asked via the Suggestion Box: Why can you dereference a COM interface pointer and pass it to a function with a Com interface reference. The call. OutputDebugString(_T(&#8220;IntfByRef::Execute &#8211; Begin\\n&#8221;)); BadBoy badone; CComPtr&lt;IDoer&gt; Doer; Doer.CoCreateInstance(CLSID_Doer, NULL, CLSCTX_INPROC_SERVER); \/\/ created a raw pointer &#8211; maybe the \/\/ smart pointer was effecting it some how. [&hellip;]<\/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-27503","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Commenter Mike Petry asked via the Suggestion Box: Why can you dereference a COM interface pointer and pass it to a function with a Com interface reference. The call. OutputDebugString(_T(&#8220;IntfByRef::Execute &#8211; Begin\\n&#8221;)); BadBoy badone; CComPtr&lt;IDoer&gt; Doer; Doer.CoCreateInstance(CLSID_Doer, NULL, CLSCTX_INPROC_SERVER); \/\/ created a raw pointer &#8211; maybe the \/\/ smart pointer was effecting it some how. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/27503","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=27503"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/27503\/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=27503"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=27503"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=27503"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}