{"id":1575,"date":"2018-08-31T23:13:49","date_gmt":"2018-09-01T06:13:49","guid":{"rendered":"http:\/\/www.elbeno.com\/blog\/?p=1575"},"modified":"2018-08-31T23:16:46","modified_gmt":"2018-09-01T06:16:46","slug":"pointer-to-member-functions-can-be-tricky","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=1575","title":{"rendered":"Pointer-to-member-functions can be tricky"},"content":{"rendered":"<p>Note: the following applies to Microsoft&#8217;s compiler only &#8212; not to GCC or Clang.<\/p>\n<p>Pointers-to-member-functions (PMFs) are a bit off the beaten track in C++. They aren&#8217;t very syntactically pleasing, and they aren&#8217;t as easy to deal with as regular pointers-to-free-functions (PFFs). But they still see use, particularly in pre-C++11 codebases or where people choose to avoid the overhead of <code>std::function<\/code> or lambdas as template arguments.<\/p>\n<p>Although idiosyncratic, the way Microsoft&#8217;s compiler implements PMFs is fairly well-known in its effects. Classes that use single inheritance can achieve PMFs the same size as PFFs, i.e. the size of a pointer. Classes that use multiple inheritance must use an implementation-defined structure, which is larger than a pointer.<\/p>\n<p><a href=\"https:\/\/godbolt.org\/z\/-juwda\">This snippet of code<\/a> illustrates the difference.<\/p>\n<p>This has all been <a href=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20040209-00\/?p=40713\">well-documented on Raymond Chen&#8217;s blog<\/a>, <em>The Old New Thing<\/em>, for years now. But given the scarcity of PMF usage, subtle dangers still lurk.<\/p>\n<p>One issue can arise when separating the definition of a PMF from its class. Let&#8217;s say we have a class defined in a header <code>a.h<\/code>:<\/p>\n<pre lang=\"cpp\">\r\nclass A\r\n{\r\n  \/\/ probably a reasonable size class; we're going to use \r\n  \/\/ PMFs for this class\r\n\r\n  \/\/ multiple inheritance is rare, and this class doesn't \r\n  \/\/ use it, so PMFs for this class will be just the size\r\n  \/\/ of a pointer\r\n};\r\n<\/pre>\n<p>Because <code>A<\/code> is a fairly large class, we might have a forward declaration for <code>A<\/code>, either in a conventionally-named header such as <code>a_fwd.h<\/code>, or just as a standalone forward declaration where pointers and references to <code>A<\/code> are used.<\/p>\n<p>Then, in another file somewhere, we have a class that uses PMFs for <code>A<\/code>:<\/p>\n<pre lang=\"cpp\">\r\nusing A_PMF = auto (A::*)() -> void;\r\n\r\nclass B\r\n{\r\n  A_PMF a_pmf;\r\n\r\n  \/\/ other stuff...  \r\n};\r\n<\/pre>\n<p>A hard-to-diagnose bug lurks here. Do you see it?<\/p>\n<p>We would assume that <code>A_PMF<\/code> is the size of a pointer. Generally, multiple inheritance is rarer than single inheritance, so this is nice, and what we normally expect from MSVC.<\/p>\n<p>However, <strong>the size of <code>A_PMF<\/code> &#8212; and therefore the size of <code>B<\/code> &#8212; differs<\/strong> depending on whether <code>A<\/code>&#8216;s class definition is known, or <code>A<\/code> is simply forward-declared!<\/p>\n<p>If <code>A<\/code> is known, the compiler knows <code>A<\/code> is using single inheritance, and therefore <code>A_PMF<\/code> can be the size of a pointer. This is our normal expectation.<\/p>\n<p>If <code>A<\/code> is forward-declared, we can still declare <code>A_PMF<\/code>. But now the compiler doesn&#8217;t know for sure that <code>A_PMF<\/code> can be the size of a pointer. <code>A<\/code> could use multiple inheritance, so the compiler must err on the side of caution and use the implementation-defined structure for <code>A_PMF<\/code>.<\/p>\n<p>This can lead to <code>B<\/code> being two different sizes in two different translation units! We could have one where <code>a.h<\/code> is included (and <code>A<\/code> is known) and one where only <code>a_fwd.h<\/code> is included. Both versions will <a href=\"https:\/\/godbolt.org\/z\/J5ERAv\">compile without warnings<\/a>, but of course, depending on what comes after <code>a_pmf<\/code> in <code>B<\/code>, the bug may not show up immediately.<\/p>\n<p>When it does show up, it may be difficult to diagnose because the debugger probably has perfect knowledge of <code>A_PMF<\/code> and will claim that it&#8217;s the size of a pointer, even when the translation unit you&#8217;re looking at compiled it differently. You can run into situations where you print a value, but when you break at the print statement, what prints is not what the debugger shows. This can be rather confusing, to say the least!<\/p>\n<p>Perhaps the moral is: if you&#8217;re going to use PMFs, declare them right next to the class they belong with, and beware forward declarations.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Note: the following applies to Microsoft&#8217;s compiler only &#8212; not to GCC or Clang. Pointers-to-member-functions (PMFs) are a bit off the beaten track in C++. They aren&#8217;t very syntactically pleasing, and they aren&#8217;t as easy to deal with as regular pointers-to-free-functions (PFFs). But they still see use, particularly in pre-C++11&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22],"tags":[],"class_list":["post-1575","post","type-post","status-publish","format-standard","hentry","category-cpp"],"_links":{"self":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1575","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1575"}],"version-history":[{"count":15,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1575\/revisions"}],"predecessor-version":[{"id":1590,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1575\/revisions\/1590"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1575"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1575"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1575"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}