Skip to content
Why is a raven like a writing desk?

Thoughts both confusing and enlightening.

Why is a raven like a writing desk?

Thoughts both confusing and enlightening.

Pointer-to-member-functions can be tricky

elbeno, 31 August, 201831 August, 2018

Note: the following applies to Microsoft’s compiler only — not to GCC or Clang.

Pointers-to-member-functions (PMFs) are a bit off the beaten track in C++. They aren’t very syntactically pleasing, and they aren’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 std::function or lambdas as template arguments.

Although idiosyncratic, the way Microsoft’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.

This snippet of code illustrates the difference.

This has all been well-documented on Raymond Chen’s blog, The Old New Thing, for years now. But given the scarcity of PMF usage, subtle dangers still lurk.

One issue can arise when separating the definition of a PMF from its class. Let’s say we have a class defined in a header a.h:

class A
{
  // probably a reasonable size class; we're going to use 
  // PMFs for this class

  // multiple inheritance is rare, and this class doesn't 
  // use it, so PMFs for this class will be just the size
  // of a pointer
};

Because A is a fairly large class, we might have a forward declaration for A, either in a conventionally-named header such as a_fwd.h, or just as a standalone forward declaration where pointers and references to A are used.

Then, in another file somewhere, we have a class that uses PMFs for A:

using A_PMF = auto (A::*)() -> void;

class B
{
  A_PMF a_pmf;

  // other stuff...  
};

A hard-to-diagnose bug lurks here. Do you see it?

We would assume that A_PMF 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.

However, the size of A_PMF — and therefore the size of B — differs depending on whether A‘s class definition is known, or A is simply forward-declared!

If A is known, the compiler knows A is using single inheritance, and therefore A_PMF can be the size of a pointer. This is our normal expectation.

If A is forward-declared, we can still declare A_PMF. But now the compiler doesn’t know for sure that A_PMF can be the size of a pointer. A could use multiple inheritance, so the compiler must err on the side of caution and use the implementation-defined structure for A_PMF.

This can lead to B being two different sizes in two different translation units! We could have one where a.h is included (and A is known) and one where only a_fwd.h is included. Both versions will compile without warnings, but of course, depending on what comes after a_pmf in B, the bug may not show up immediately.

When it does show up, it may be difficult to diagnose because the debugger probably has perfect knowledge of A_PMF and will claim that it’s the size of a pointer, even when the translation unit you’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!

Perhaps the moral is: if you’re going to use PMFs, declare them right next to the class they belong with, and beware forward declarations.

C++

Post navigation

Previous post
Next post

Related Posts

Formatted Diagnostics with C++20

10 December, 202410 December, 2024

C++26 adds formatted diagnostics with static_assert, something like this: The benefit of course is that when such an assertion fails, the compiler outputs a diagnostic that we control. But can this be done in C++20? Well, this is C++! So the answer is a qualified yes – we can get…

Read More

How to print anything in C++ (part 3)

2 February, 201530 June, 2015

Part 1 Part 2 Part 3 Part 4 Part 5 Postscript So far, we’ve dealt with things that are already outputtable with operator<<, and things that are iterable with begin() and end(). To round out the “containers”, we need to deal with pair and tuple. It’s simple to print a…

Read More

C++ Reflection: Another Monad

4 March, 20264 March, 2026

“Discovery consists of seeing what everybody has seen, and thinking what nobody has thought.” — Albert Szent-Györgi, 1937 Nobel Laureate for Medicine I’m sure others have thought this, but they’re certainly not saying much about it. Barry’s recent blog post “Behold the power of meta::substitute” got so close to saying…

Read More

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

©2026 Why is a raven like a writing desk? | WordPress Theme by SuperbThemes